diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/pci/Kconfig | 1 | ||||
-rw-r--r-- | drivers/pci/pci_tegra.c | 163 |
2 files changed, 159 insertions, 5 deletions
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 26aa2b0..669e37b 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -31,6 +31,7 @@ config PCI_SANDBOX config PCI_TEGRA bool "Tegra PCI support" depends on TEGRA + depends on (TEGRA186 && POWER_DOMAIN) || (!TEGRA186) help Enable support for the PCIe controller found on some generations of Tegra. Tegra20 has 2 root ports with a total of 4 lanes, Tegra30 has diff --git a/drivers/pci/pci_tegra.c b/drivers/pci/pci_tegra.c index 352cdef..ea8adb98 100644 --- a/drivers/pci/pci_tegra.c +++ b/drivers/pci/pci_tegra.c @@ -13,22 +13,35 @@ #define pr_fmt(fmt) "tegra-pcie: " fmt #include <common.h> +#include <clk.h> #include <dm.h> #include <errno.h> #include <fdtdec.h> #include <malloc.h> #include <pci.h> +#include <power-domain.h> +#include <reset.h> #include <asm/io.h> #include <asm/gpio.h> +#include <linux/list.h> + +#ifndef CONFIG_TEGRA186 #include <asm/arch/clock.h> #include <asm/arch/powergate.h> #include <asm/arch-tegra/xusb-padctl.h> - -#include <linux/list.h> - #include <dt-bindings/pinctrl/pinctrl-tegra-xusb.h> +#endif + +/* + * FIXME: TODO: This driver contains a number of ifdef CONFIG_TEGRA186 that + * should not be present. These are needed because newer Tegra SoCs support + * only the standard clock/reset APIs, whereas older Tegra SoCs support only + * a custom Tegra-specific API. ASAP the older Tegra SoCs' code should be + * fixed to implement the standard APIs, and all drivers converted to solely + * use the new standard APIs, with no ifdefs. + */ DECLARE_GLOBAL_DATA_PTR; @@ -103,6 +116,9 @@ DECLARE_GLOBAL_DATA_PTR; #define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_222 (0x1 << 20) #define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X4_X1 (0x1 << 20) #define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_411 (0x2 << 20) +#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_401 (0x0 << 20) +#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_211 (0x1 << 20) +#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_111 (0x2 << 20) #define AFI_FUSE 0x104 #define AFI_FUSE_PCIE_T0_GEN2_DIS (1 << 2) @@ -110,6 +126,7 @@ DECLARE_GLOBAL_DATA_PTR; #define AFI_PEX0_CTRL 0x110 #define AFI_PEX1_CTRL 0x118 #define AFI_PEX2_CTRL 0x128 +#define AFI_PEX2_CTRL_T186 0x19c #define AFI_PEX_CTRL_RST (1 << 0) #define AFI_PEX_CTRL_CLKREQ_EN (1 << 1) #define AFI_PEX_CTRL_REFCLK_EN (1 << 3) @@ -173,6 +190,7 @@ enum tegra_pci_id { TEGRA30_PCIE, TEGRA124_PCIE, TEGRA210_PCIE, + TEGRA186_PCIE, }; struct tegra_pcie_port { @@ -189,6 +207,7 @@ struct tegra_pcie_soc { unsigned int num_ports; unsigned long pads_pll_ctl; unsigned long tx_ref_sel; + unsigned long afi_pex2_ctrl; u32 pads_refclk_cfg0; u32 pads_refclk_cfg1; bool has_pex_clkreq_en; @@ -209,7 +228,17 @@ struct tegra_pcie { unsigned long xbar; const struct tegra_pcie_soc *soc; + +#ifdef CONFIG_TEGRA186 + struct clk clk_afi; + struct clk clk_pex; + struct reset_ctl reset_afi; + struct reset_ctl reset_pex; + struct reset_ctl reset_pcie_x; + struct power_domain pwrdom; +#else struct tegra_xusb_phy *phy; +#endif }; static void afi_writel(struct tegra_pcie *pcie, unsigned long value, @@ -229,10 +258,12 @@ static void pads_writel(struct tegra_pcie *pcie, unsigned long value, writel(value, pcie->pads.start + offset); } +#ifndef CONFIG_TEGRA186 static unsigned long pads_readl(struct tegra_pcie *pcie, unsigned long offset) { return readl(pcie->pads.start + offset); } +#endif static unsigned long rp_readl(struct tegra_pcie_port *port, unsigned long offset) @@ -400,6 +431,24 @@ static int tegra_pcie_get_xbar_config(const void *fdt, int node, u32 lanes, return 0; } break; + case TEGRA186_PCIE: + switch (lanes) { + case 0x0010004: + debug("x4 x1 configuration\n"); + *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_401; + return 0; + + case 0x0010102: + debug("x2 x1 x1 configuration\n"); + *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_211; + return 0; + + case 0x0010101: + debug("x1 x1 x1 configuration\n"); + *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_T186_111; + return 0; + } + break; default: break; } @@ -471,6 +520,7 @@ static int tegra_pcie_parse_dt(const void *fdt, int node, enum tegra_pci_id id, return err; } +#ifndef CONFIG_TEGRA186 pcie->phy = tegra_xusb_phy_get(TEGRA_XUSB_PADCTL_PCIE); if (pcie->phy) { err = tegra_xusb_phy_prepare(pcie->phy); @@ -479,6 +529,7 @@ static int tegra_pcie_parse_dt(const void *fdt, int node, enum tegra_pci_id id, return err; } } +#endif fdt_for_each_subnode(fdt, subnode, node) { unsigned int index = 0, num_lanes = 0; @@ -523,6 +574,44 @@ static int tegra_pcie_parse_dt(const void *fdt, int node, enum tegra_pci_id id, return 0; } +#ifdef CONFIG_TEGRA186 +static int tegra_pcie_power_on(struct tegra_pcie *pcie) +{ + int ret; + + ret = power_domain_on(&pcie->pwrdom); + if (ret) { + error("power_domain_on() failed: %d\n", ret); + return ret; + } + + ret = clk_enable(&pcie->clk_afi); + if (ret) { + error("clk_enable(afi) failed: %d\n", ret); + return ret; + } + + ret = clk_enable(&pcie->clk_pex); + if (ret) { + error("clk_enable(pex) failed: %d\n", ret); + return ret; + } + + ret = reset_deassert(&pcie->reset_afi); + if (ret) { + error("reset_deassert(afi) failed: %d\n", ret); + return ret; + } + + ret = reset_deassert(&pcie->reset_pex); + if (ret) { + error("reset_deassert(pex) failed: %d\n", ret); + return ret; + } + + return 0; +} +#else static int tegra_pcie_power_on(struct tegra_pcie *pcie) { const struct tegra_pcie_soc *soc = pcie->soc; @@ -639,6 +728,7 @@ static int tegra_pcie_phy_enable(struct tegra_pcie *pcie) return 0; } +#endif static int tegra_pcie_enable_controller(struct tegra_pcie *pcie) { @@ -647,7 +737,11 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie) u32 value; int err; +#ifdef CONFIG_TEGRA186 + { +#else if (pcie->phy) { +#endif value = afi_readl(pcie, AFI_PLLE_CONTROL); value &= ~AFI_PLLE_CONTROL_BYPASS_PADS2PLLE_CONTROL; value |= AFI_PLLE_CONTROL_PADS2PLLE_CONTROL_EN; @@ -675,6 +769,7 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie) afi_writel(pcie, value, AFI_FUSE); +#ifndef CONFIG_TEGRA186 if (pcie->phy) err = tegra_xusb_phy_enable(pcie->phy); else @@ -684,9 +779,18 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie) error("failed to power on PHY: %d\n", err); return err; } +#endif /* take the PCIEXCLK logic out of reset */ +#ifdef CONFIG_TEGRA186 + err = reset_deassert(&pcie->reset_pcie_x); + if (err) { + error("reset_deassert(pcie_x) failed: %d\n", err); + return err; + } +#else reset_set_enable(PERIPH_ID_PCIEXCLK, 0); +#endif /* finally enable PCIe */ value = afi_readl(pcie, AFI_CONFIGURATION); @@ -787,7 +891,7 @@ static unsigned long tegra_pcie_port_get_pex_ctrl(struct tegra_pcie_port *port) break; case 2: - ret = AFI_PEX2_CTRL; + ret = port->pcie->soc->afi_pex2_ctrl; break; } @@ -945,6 +1049,7 @@ static const struct tegra_pcie_soc pci_tegra_soc[] = { .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, @@ -972,7 +1077,16 @@ static const struct tegra_pcie_soc pci_tegra_soc[] = { .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) @@ -996,6 +1110,44 @@ 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"); @@ -1033,6 +1185,7 @@ static const struct udevice_id pci_tegra_ids[] = { { .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 }, { } }; |