diff options
author | Manikanta Maddireddy <mmaddireddy@nvidia.com> | 2017-09-27 07:58:35 -0400 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2017-10-18 12:27:17 -0400 |
commit | 9cea513d8cbc75ee26327d3d8971fe7b58288d8f (patch) | |
tree | f80f38100f8c3e5e22e194fd17ced2194037e2fb | |
parent | 904fb8e452b4a95490357841291fa523ad1d6442 (diff) |
PCI: tegra: Add Tegra186 PCIe support
Add Tegra186 PCIe support. UPHY programming is performed by BPMP; PHY
enable calls are not required for Tegra186 PCIe.
Power partition ungate is done by BPMP powergate driver. The Tegra186
DT description must include a "power-domains" property, which results in
dev->pm_domain being set.
Tested-by: Mikko Perttunen <mperttunen@nvidia.com>
Tested-by: Thierry Reding <treding@nvidia.com>
Signed-off-by: Manikanta Maddireddy <mmaddireddy@nvidia.com>
[bhelgaas: add "power-domains" reference]
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Mikko Perttunen <mperttunen@nvidia.com>
Acked-by: Thierry Reding <treding@nvidia.com>
-rw-r--r-- | drivers/pci/host/pci-tegra.c | 134 |
1 files changed, 109 insertions, 25 deletions
diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c index e8e1ddbaabc9..8dd3b3f7d141 100644 --- a/drivers/pci/host/pci-tegra.c +++ b/drivers/pci/host/pci-tegra.c | |||
@@ -159,10 +159,13 @@ | |||
159 | #define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_SINGLE (0x0 << 20) | 159 | #define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_SINGLE (0x0 << 20) |
160 | #define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_420 (0x0 << 20) | 160 | #define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_420 (0x0 << 20) |
161 | #define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X2_X1 (0x0 << 20) | 161 | #define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X2_X1 (0x0 << 20) |
162 | #define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_401 (0x0 << 20) | ||
162 | #define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_DUAL (0x1 << 20) | 163 | #define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_DUAL (0x1 << 20) |
163 | #define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_222 (0x1 << 20) | 164 | #define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_222 (0x1 << 20) |
164 | #define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X4_X1 (0x1 << 20) | 165 | #define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X4_X1 (0x1 << 20) |
166 | #define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_211 (0x1 << 20) | ||
165 | #define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_411 (0x2 << 20) | 167 | #define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_411 (0x2 << 20) |
168 | #define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_111 (0x2 << 20) | ||
166 | 169 | ||
167 | #define AFI_FUSE 0x104 | 170 | #define AFI_FUSE 0x104 |
168 | #define AFI_FUSE_PCIE_T0_GEN2_DIS (1 << 2) | 171 | #define AFI_FUSE_PCIE_T0_GEN2_DIS (1 << 2) |
@@ -252,6 +255,7 @@ struct tegra_pcie_soc { | |||
252 | bool has_cml_clk; | 255 | bool has_cml_clk; |
253 | bool has_gen2; | 256 | bool has_gen2; |
254 | bool force_pca_enable; | 257 | bool force_pca_enable; |
258 | bool program_uphy; | ||
255 | }; | 259 | }; |
256 | 260 | ||
257 | static inline struct tegra_msi *to_tegra_msi(struct msi_controller *chip) | 261 | static inline struct tegra_msi *to_tegra_msi(struct msi_controller *chip) |
@@ -1032,10 +1036,12 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie) | |||
1032 | afi_writel(pcie, value, AFI_FUSE); | 1036 | afi_writel(pcie, value, AFI_FUSE); |
1033 | } | 1037 | } |
1034 | 1038 | ||
1035 | err = tegra_pcie_phy_power_on(pcie); | 1039 | if (soc->program_uphy) { |
1036 | if (err < 0) { | 1040 | err = tegra_pcie_phy_power_on(pcie); |
1037 | dev_err(dev, "failed to power on PHY(s): %d\n", err); | 1041 | if (err < 0) { |
1038 | return err; | 1042 | dev_err(dev, "failed to power on PHY(s): %d\n", err); |
1043 | return err; | ||
1044 | } | ||
1039 | } | 1045 | } |
1040 | 1046 | ||
1041 | /* take the PCIe interface module out of reset */ | 1047 | /* take the PCIe interface module out of reset */ |
@@ -1068,19 +1074,23 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie) | |||
1068 | static void tegra_pcie_power_off(struct tegra_pcie *pcie) | 1074 | static void tegra_pcie_power_off(struct tegra_pcie *pcie) |
1069 | { | 1075 | { |
1070 | struct device *dev = pcie->dev; | 1076 | struct device *dev = pcie->dev; |
1077 | const struct tegra_pcie_soc *soc = pcie->soc; | ||
1071 | int err; | 1078 | int err; |
1072 | 1079 | ||
1073 | /* TODO: disable and unprepare clocks? */ | 1080 | /* TODO: disable and unprepare clocks? */ |
1074 | 1081 | ||
1075 | err = tegra_pcie_phy_power_off(pcie); | 1082 | if (soc->program_uphy) { |
1076 | if (err < 0) | 1083 | err = tegra_pcie_phy_power_off(pcie); |
1077 | dev_err(dev, "failed to power off PHY(s): %d\n", err); | 1084 | if (err < 0) |
1085 | dev_err(dev, "failed to power off PHY(s): %d\n", err); | ||
1086 | } | ||
1078 | 1087 | ||
1079 | reset_control_assert(pcie->pcie_xrst); | 1088 | reset_control_assert(pcie->pcie_xrst); |
1080 | reset_control_assert(pcie->afi_rst); | 1089 | reset_control_assert(pcie->afi_rst); |
1081 | reset_control_assert(pcie->pex_rst); | 1090 | reset_control_assert(pcie->pex_rst); |
1082 | 1091 | ||
1083 | tegra_powergate_power_off(TEGRA_POWERGATE_PCIE); | 1092 | if (!dev->pm_domain) |
1093 | tegra_powergate_power_off(TEGRA_POWERGATE_PCIE); | ||
1084 | 1094 | ||
1085 | err = regulator_bulk_disable(pcie->num_supplies, pcie->supplies); | 1095 | err = regulator_bulk_disable(pcie->num_supplies, pcie->supplies); |
1086 | if (err < 0) | 1096 | if (err < 0) |
@@ -1097,19 +1107,29 @@ static int tegra_pcie_power_on(struct tegra_pcie *pcie) | |||
1097 | reset_control_assert(pcie->afi_rst); | 1107 | reset_control_assert(pcie->afi_rst); |
1098 | reset_control_assert(pcie->pex_rst); | 1108 | reset_control_assert(pcie->pex_rst); |
1099 | 1109 | ||
1100 | tegra_powergate_power_off(TEGRA_POWERGATE_PCIE); | 1110 | if (!dev->pm_domain) |
1111 | tegra_powergate_power_off(TEGRA_POWERGATE_PCIE); | ||
1101 | 1112 | ||
1102 | /* enable regulators */ | 1113 | /* enable regulators */ |
1103 | err = regulator_bulk_enable(pcie->num_supplies, pcie->supplies); | 1114 | err = regulator_bulk_enable(pcie->num_supplies, pcie->supplies); |
1104 | if (err < 0) | 1115 | if (err < 0) |
1105 | dev_err(dev, "failed to enable regulators: %d\n", err); | 1116 | dev_err(dev, "failed to enable regulators: %d\n", err); |
1106 | 1117 | ||
1107 | err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCIE, | 1118 | if (dev->pm_domain) { |
1108 | pcie->pex_clk, | 1119 | err = clk_prepare_enable(pcie->pex_clk); |
1109 | pcie->pex_rst); | 1120 | if (err) { |
1110 | if (err) { | 1121 | dev_err(dev, "failed to enable PEX clock: %d\n", err); |
1111 | dev_err(dev, "powerup sequence failed: %d\n", err); | 1122 | return err; |
1112 | return err; | 1123 | } |
1124 | reset_control_deassert(pcie->pex_rst); | ||
1125 | } else { | ||
1126 | err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCIE, | ||
1127 | pcie->pex_clk, | ||
1128 | pcie->pex_rst); | ||
1129 | if (err) { | ||
1130 | dev_err(dev, "powerup sequence failed: %d\n", err); | ||
1131 | return err; | ||
1132 | } | ||
1113 | } | 1133 | } |
1114 | 1134 | ||
1115 | reset_control_deassert(pcie->afi_rst); | 1135 | reset_control_deassert(pcie->afi_rst); |
@@ -1282,6 +1302,7 @@ static int tegra_pcie_get_resources(struct tegra_pcie *pcie) | |||
1282 | struct device *dev = pcie->dev; | 1302 | struct device *dev = pcie->dev; |
1283 | struct platform_device *pdev = to_platform_device(dev); | 1303 | struct platform_device *pdev = to_platform_device(dev); |
1284 | struct resource *pads, *afi, *res; | 1304 | struct resource *pads, *afi, *res; |
1305 | const struct tegra_pcie_soc *soc = pcie->soc; | ||
1285 | int err; | 1306 | int err; |
1286 | 1307 | ||
1287 | err = tegra_pcie_clocks_get(pcie); | 1308 | err = tegra_pcie_clocks_get(pcie); |
@@ -1296,10 +1317,12 @@ static int tegra_pcie_get_resources(struct tegra_pcie *pcie) | |||
1296 | return err; | 1317 | return err; |
1297 | } | 1318 | } |
1298 | 1319 | ||
1299 | err = tegra_pcie_phys_get(pcie); | 1320 | if (soc->program_uphy) { |
1300 | if (err < 0) { | 1321 | err = tegra_pcie_phys_get(pcie); |
1301 | dev_err(dev, "failed to get PHYs: %d\n", err); | 1322 | if (err < 0) { |
1302 | return err; | 1323 | dev_err(dev, "failed to get PHYs: %d\n", err); |
1324 | return err; | ||
1325 | } | ||
1303 | } | 1326 | } |
1304 | 1327 | ||
1305 | err = tegra_pcie_power_on(pcie); | 1328 | err = tegra_pcie_power_on(pcie); |
@@ -1361,6 +1384,7 @@ poweroff: | |||
1361 | static int tegra_pcie_put_resources(struct tegra_pcie *pcie) | 1384 | static int tegra_pcie_put_resources(struct tegra_pcie *pcie) |
1362 | { | 1385 | { |
1363 | struct device *dev = pcie->dev; | 1386 | struct device *dev = pcie->dev; |
1387 | const struct tegra_pcie_soc *soc = pcie->soc; | ||
1364 | int err; | 1388 | int err; |
1365 | 1389 | ||
1366 | if (pcie->irq > 0) | 1390 | if (pcie->irq > 0) |
@@ -1368,9 +1392,11 @@ static int tegra_pcie_put_resources(struct tegra_pcie *pcie) | |||
1368 | 1392 | ||
1369 | tegra_pcie_power_off(pcie); | 1393 | tegra_pcie_power_off(pcie); |
1370 | 1394 | ||
1371 | err = phy_exit(pcie->phy); | 1395 | if (soc->program_uphy) { |
1372 | if (err < 0) | 1396 | err = phy_exit(pcie->phy); |
1373 | dev_err(dev, "failed to teardown PHY: %d\n", err); | 1397 | if (err < 0) |
1398 | dev_err(dev, "failed to teardown PHY: %d\n", err); | ||
1399 | } | ||
1374 | 1400 | ||
1375 | return 0; | 1401 | return 0; |
1376 | } | 1402 | } |
@@ -1636,8 +1662,32 @@ static int tegra_pcie_get_xbar_config(struct tegra_pcie *pcie, u32 lanes, | |||
1636 | struct device *dev = pcie->dev; | 1662 | struct device *dev = pcie->dev; |
1637 | struct device_node *np = dev->of_node; | 1663 | struct device_node *np = dev->of_node; |
1638 | 1664 | ||
1639 | if (of_device_is_compatible(np, "nvidia,tegra124-pcie") || | 1665 | if (of_device_is_compatible(np, "nvidia,tegra186-pcie")) { |
1640 | of_device_is_compatible(np, "nvidia,tegra210-pcie")) { | 1666 | switch (lanes) { |
1667 | case 0x010004: | ||
1668 | dev_info(dev, "4x1, 1x1 configuration\n"); | ||
1669 | *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_401; | ||
1670 | return 0; | ||
1671 | |||
1672 | case 0x010102: | ||
1673 | dev_info(dev, "2x1, 1X1, 1x1 configuration\n"); | ||
1674 | *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_211; | ||
1675 | return 0; | ||
1676 | |||
1677 | case 0x010101: | ||
1678 | dev_info(dev, "1x1, 1x1, 1x1 configuration\n"); | ||
1679 | *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_111; | ||
1680 | return 0; | ||
1681 | |||
1682 | default: | ||
1683 | dev_info(dev, "wrong configuration updated in DT, " | ||
1684 | "switching to default 2x1, 1x1, 1x1 " | ||
1685 | "configuration\n"); | ||
1686 | *xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_211; | ||
1687 | return 0; | ||
1688 | } | ||
1689 | } else if (of_device_is_compatible(np, "nvidia,tegra124-pcie") || | ||
1690 | of_device_is_compatible(np, "nvidia,tegra210-pcie")) { | ||
1641 | switch (lanes) { | 1691 | switch (lanes) { |
1642 | case 0x0000104: | 1692 | case 0x0000104: |
1643 | dev_info(dev, "4x1, 1x1 configuration\n"); | 1693 | dev_info(dev, "4x1, 1x1 configuration\n"); |
@@ -1757,7 +1807,20 @@ static int tegra_pcie_get_regulators(struct tegra_pcie *pcie, u32 lane_mask) | |||
1757 | struct device_node *np = dev->of_node; | 1807 | struct device_node *np = dev->of_node; |
1758 | unsigned int i = 0; | 1808 | unsigned int i = 0; |
1759 | 1809 | ||
1760 | if (of_device_is_compatible(np, "nvidia,tegra210-pcie")) { | 1810 | if (of_device_is_compatible(np, "nvidia,tegra186-pcie")) { |
1811 | pcie->num_supplies = 4; | ||
1812 | |||
1813 | pcie->supplies = devm_kcalloc(pcie->dev, pcie->num_supplies, | ||
1814 | sizeof(*pcie->supplies), | ||
1815 | GFP_KERNEL); | ||
1816 | if (!pcie->supplies) | ||
1817 | return -ENOMEM; | ||
1818 | |||
1819 | pcie->supplies[i++].supply = "dvdd-pex"; | ||
1820 | pcie->supplies[i++].supply = "hvdd-pex-pll"; | ||
1821 | pcie->supplies[i++].supply = "hvdd-pex"; | ||
1822 | pcie->supplies[i++].supply = "vddio-pexctl-aud"; | ||
1823 | } else if (of_device_is_compatible(np, "nvidia,tegra210-pcie")) { | ||
1761 | pcie->num_supplies = 6; | 1824 | pcie->num_supplies = 6; |
1762 | 1825 | ||
1763 | pcie->supplies = devm_kcalloc(pcie->dev, pcie->num_supplies, | 1826 | pcie->supplies = devm_kcalloc(pcie->dev, pcie->num_supplies, |
@@ -2096,6 +2159,7 @@ static const struct tegra_pcie_soc tegra20_pcie = { | |||
2096 | .has_cml_clk = false, | 2159 | .has_cml_clk = false, |
2097 | .has_gen2 = false, | 2160 | .has_gen2 = false, |
2098 | .force_pca_enable = false, | 2161 | .force_pca_enable = false, |
2162 | .program_uphy = true, | ||
2099 | }; | 2163 | }; |
2100 | 2164 | ||
2101 | static const struct tegra_pcie_soc tegra30_pcie = { | 2165 | static const struct tegra_pcie_soc tegra30_pcie = { |
@@ -2111,6 +2175,7 @@ static const struct tegra_pcie_soc tegra30_pcie = { | |||
2111 | .has_cml_clk = true, | 2175 | .has_cml_clk = true, |
2112 | .has_gen2 = false, | 2176 | .has_gen2 = false, |
2113 | .force_pca_enable = false, | 2177 | .force_pca_enable = false, |
2178 | .program_uphy = true, | ||
2114 | }; | 2179 | }; |
2115 | 2180 | ||
2116 | static const struct tegra_pcie_soc tegra124_pcie = { | 2181 | static const struct tegra_pcie_soc tegra124_pcie = { |
@@ -2125,6 +2190,7 @@ static const struct tegra_pcie_soc tegra124_pcie = { | |||
2125 | .has_cml_clk = true, | 2190 | .has_cml_clk = true, |
2126 | .has_gen2 = true, | 2191 | .has_gen2 = true, |
2127 | .force_pca_enable = false, | 2192 | .force_pca_enable = false, |
2193 | .program_uphy = true, | ||
2128 | }; | 2194 | }; |
2129 | 2195 | ||
2130 | static const struct tegra_pcie_soc tegra210_pcie = { | 2196 | static const struct tegra_pcie_soc tegra210_pcie = { |
@@ -2139,9 +2205,27 @@ static const struct tegra_pcie_soc tegra210_pcie = { | |||
2139 | .has_cml_clk = true, | 2205 | .has_cml_clk = true, |
2140 | .has_gen2 = true, | 2206 | .has_gen2 = true, |
2141 | .force_pca_enable = true, | 2207 | .force_pca_enable = true, |
2208 | .program_uphy = true, | ||
2209 | }; | ||
2210 | |||
2211 | static const struct tegra_pcie_soc tegra186_pcie = { | ||
2212 | .num_ports = 3, | ||
2213 | .msi_base_shift = 8, | ||
2214 | .pads_pll_ctl = PADS_PLL_CTL_TEGRA30, | ||
2215 | .tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN, | ||
2216 | .pads_refclk_cfg0 = 0x80b880b8, | ||
2217 | .pads_refclk_cfg1 = 0x000480b8, | ||
2218 | .has_pex_clkreq_en = true, | ||
2219 | .has_pex_bias_ctrl = true, | ||
2220 | .has_intr_prsnt_sense = true, | ||
2221 | .has_cml_clk = false, | ||
2222 | .has_gen2 = true, | ||
2223 | .force_pca_enable = false, | ||
2224 | .program_uphy = false, | ||
2142 | }; | 2225 | }; |
2143 | 2226 | ||
2144 | static const struct of_device_id tegra_pcie_of_match[] = { | 2227 | static const struct of_device_id tegra_pcie_of_match[] = { |
2228 | { .compatible = "nvidia,tegra186-pcie", .data = &tegra186_pcie }, | ||
2145 | { .compatible = "nvidia,tegra210-pcie", .data = &tegra210_pcie }, | 2229 | { .compatible = "nvidia,tegra210-pcie", .data = &tegra210_pcie }, |
2146 | { .compatible = "nvidia,tegra124-pcie", .data = &tegra124_pcie }, | 2230 | { .compatible = "nvidia,tegra124-pcie", .data = &tegra124_pcie }, |
2147 | { .compatible = "nvidia,tegra30-pcie", .data = &tegra30_pcie }, | 2231 | { .compatible = "nvidia,tegra30-pcie", .data = &tegra30_pcie }, |