Skip to content
Snippets Groups Projects
pci_tegra.c 28.3 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	afi_writel(port->pcie, value, ctrl);
    
    	/* disable reference clock */
    	value = afi_readl(port->pcie, ctrl);
    	value &= ~AFI_PEX_CTRL_REFCLK_EN;
    	afi_writel(port->pcie, value, ctrl);
    }
    
    static void tegra_pcie_port_free(struct tegra_pcie_port *port)
    {
    	list_del(&port->list);
    	free(port);
    }
    
    static int tegra_pcie_enable(struct tegra_pcie *pcie)
    {
    	struct tegra_pcie_port *port, *tmp;
    
    	list_for_each_entry_safe(port, tmp, &pcie->ports, list) {
    		debug("probing port %u, using %u lanes\n", port->index,
    		      port->num_lanes);
    
    		tegra_pcie_port_enable(port);
    
    		if (tegra_pcie_port_check_link(port))
    			continue;
    
    		debug("link %u down, ignoring\n", port->index);
    
    		tegra_pcie_port_disable(port);
    		tegra_pcie_port_free(port);
    	}
    
    	return 0;
    }
    
    
    static const struct tegra_pcie_soc pci_tegra_soc[] = {
    	[TEGRA20_PCIE] = {
    		.num_ports = 2,
    		.pads_pll_ctl = PADS_PLL_CTL_TEGRA20,
    		.tx_ref_sel = PADS_PLL_CTL_TXCLKREF_DIV10,
    
    		.pads_refclk_cfg0 = 0xfa5cfa5c,
    
    		.has_pex_clkreq_en = false,
    		.has_pex_bias_ctrl = false,
    		.has_cml_clk = false,
    		.has_gen2 = false,
    	},
    	[TEGRA30_PCIE] = {
    		.num_ports = 3,
    		.pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
    		.tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
    
    		.afi_pex2_ctrl = AFI_PEX2_CTRL,
    
    		.pads_refclk_cfg0 = 0xfa5cfa5c,
    		.pads_refclk_cfg1 = 0xfa5cfa5c,
    
    		.has_pex_clkreq_en = true,
    		.has_pex_bias_ctrl = true,
    		.has_cml_clk = true,
    		.has_gen2 = false,
    	},
    	[TEGRA124_PCIE] = {
    		.num_ports = 2,
    		.pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
    		.tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
    
    		.pads_refclk_cfg0 = 0x44ac44ac,
    
    		.has_pex_clkreq_en = true,
    		.has_pex_bias_ctrl = true,
    		.has_cml_clk = true,
    		.has_gen2 = true,
    	},
    	[TEGRA210_PCIE] = {
    		.num_ports = 2,
    		.pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
    		.tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
    
    		.pads_refclk_cfg0 = 0x90b890b8,
    
    		.has_pex_clkreq_en = true,
    		.has_pex_bias_ctrl = true,
    		.has_cml_clk = true,
    		.has_gen2 = true,
    		.force_pca_enable = true,
    
    	},
    	[TEGRA186_PCIE] = {
    		.num_ports = 3,
    		.afi_pex2_ctrl = AFI_PEX2_CTRL_T186,
    		.pads_refclk_cfg0 = 0x80b880b8,
    		.pads_refclk_cfg1 = 0x000480b8,
    		.has_pex_clkreq_en = true,
    		.has_pex_bias_ctrl = true,
    		.has_gen2 = true,
    	},
    
    static int pci_tegra_ofdata_to_platdata(struct udevice *dev)
    
    	struct tegra_pcie *pcie = dev_get_priv(dev);
    	enum tegra_pci_id id;
    
    	id = dev_get_driver_data(dev);
    	pcie->soc = &pci_tegra_soc[id];
    
    	INIT_LIST_HEAD(&pcie->ports);
    
    	if (tegra_pcie_parse_dt(gd->fdt_blob, dev_of_offset(dev), id, pcie))
    
    static int pci_tegra_probe(struct udevice *dev)
    {
    	struct tegra_pcie *pcie = dev_get_priv(dev);
    	int err;
    
    #ifdef CONFIG_TEGRA186
    	err = clk_get_by_name(dev, "afi", &pcie->clk_afi);
    	if (err) {
    		debug("clk_get_by_name(afi) failed: %d\n", err);
    		return err;
    	}
    
    	err = clk_get_by_name(dev, "pex", &pcie->clk_pex);
    	if (err) {
    		debug("clk_get_by_name(pex) failed: %d\n", err);
    		return err;
    	}
    
    	err = reset_get_by_name(dev, "afi", &pcie->reset_afi);
    	if (err) {
    		debug("reset_get_by_name(afi) failed: %d\n", err);
    		return err;
    	}
    
    	err = reset_get_by_name(dev, "pex", &pcie->reset_pex);
    	if (err) {
    		debug("reset_get_by_name(pex) failed: %d\n", err);
    		return err;
    	}
    
    	err = reset_get_by_name(dev, "pcie_x", &pcie->reset_pcie_x);
    	if (err) {
    		debug("reset_get_by_name(pcie_x) failed: %d\n", err);
    		return err;
    	}
    
    	err = power_domain_get(dev, &pcie->pwrdom);
    	if (err) {
    		debug("power_domain_get() failed: %d\n", err);
    		return err;
    	}
    #endif
    
    
    	err = tegra_pcie_power_on(pcie);
    	if (err < 0) {
    		error("failed to power on");
    		return err;
    	}
    
    	err = tegra_pcie_enable_controller(pcie);
    	if (err < 0) {
    		error("failed to enable controller");
    		return err;
    	}
    
    	err = tegra_pcie_setup_translations(dev);
    	if (err < 0) {
    		error("failed to decode ranges");
    		return err;
    	}
    
    	err = tegra_pcie_enable(pcie);
    	if (err < 0) {
    		error("failed to enable PCIe");
    		return err;
    
    static const struct dm_pci_ops pci_tegra_ops = {
    	.read_config	= pci_tegra_read_config,
    	.write_config	= pci_tegra_write_config,
    };
    
    static const struct udevice_id pci_tegra_ids[] = {
    	{ .compatible = "nvidia,tegra20-pcie", .data = TEGRA20_PCIE },
    	{ .compatible = "nvidia,tegra30-pcie", .data = TEGRA30_PCIE },
    	{ .compatible = "nvidia,tegra124-pcie", .data = TEGRA124_PCIE },
    	{ .compatible = "nvidia,tegra210-pcie", .data = TEGRA210_PCIE },
    
    	{ .compatible = "nvidia,tegra186-pcie", .data = TEGRA186_PCIE },
    
    U_BOOT_DRIVER(pci_tegra) = {
    	.name	= "pci_tegra",
    	.id	= UCLASS_PCI,
    	.of_match = pci_tegra_ids,
    	.ops	= &pci_tegra_ops,
    	.ofdata_to_platdata = pci_tegra_ofdata_to_platdata,
    	.probe	= pci_tegra_probe,
    	.priv_auto_alloc_size = sizeof(struct tegra_pcie),
    };