diff options
author | Thierry Reding <treding@nvidia.com> | 2015-11-11 12:25:59 -0500 |
---|---|---|
committer | Thierry Reding <treding@nvidia.com> | 2016-04-29 10:47:54 -0400 |
commit | 6fe7c187e026c8b610df9dda7d9befc70cbfd169 (patch) | |
tree | b5ae969b5d592750dd48c9e4e1b89ccdd060d2a8 | |
parent | 13541cc3d42faef262cbae21331128c065d7dc5d (diff) |
PCI: tegra: Support per-lane PHYs
The current XUSB pad controller bindings are insufficient to describe
PHY devices attached to USB controllers. New bindings have been created
to overcome these restrictions. As a side-effect each root port now is
assigned a set of PHY devices, one for each lane associated with the
root port. This has the benefit of allowing fine-grained control of the
power management for each lane.
Acked-by: Stephen Warren <swarren@nvidia.com>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>
-rw-r--r-- | drivers/pci/host/pci-tegra.c | 244 |
1 files changed, 227 insertions, 17 deletions
diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c index 68d1f41b3cbf..c388468c202a 100644 --- a/drivers/pci/host/pci-tegra.c +++ b/drivers/pci/host/pci-tegra.c | |||
@@ -295,6 +295,7 @@ struct tegra_pcie { | |||
295 | struct reset_control *afi_rst; | 295 | struct reset_control *afi_rst; |
296 | struct reset_control *pcie_xrst; | 296 | struct reset_control *pcie_xrst; |
297 | 297 | ||
298 | bool legacy_phy; | ||
298 | struct phy *phy; | 299 | struct phy *phy; |
299 | 300 | ||
300 | struct tegra_msi msi; | 301 | struct tegra_msi msi; |
@@ -311,11 +312,14 @@ struct tegra_pcie { | |||
311 | 312 | ||
312 | struct tegra_pcie_port { | 313 | struct tegra_pcie_port { |
313 | struct tegra_pcie *pcie; | 314 | struct tegra_pcie *pcie; |
315 | struct device_node *np; | ||
314 | struct list_head list; | 316 | struct list_head list; |
315 | struct resource regs; | 317 | struct resource regs; |
316 | void __iomem *base; | 318 | void __iomem *base; |
317 | unsigned int index; | 319 | unsigned int index; |
318 | unsigned int lanes; | 320 | unsigned int lanes; |
321 | |||
322 | struct phy **phys; | ||
319 | }; | 323 | }; |
320 | 324 | ||
321 | struct tegra_pcie_bus { | 325 | struct tegra_pcie_bus { |
@@ -860,6 +864,128 @@ static int tegra_pcie_phy_enable(struct tegra_pcie *pcie) | |||
860 | return 0; | 864 | return 0; |
861 | } | 865 | } |
862 | 866 | ||
867 | static int tegra_pcie_phy_disable(struct tegra_pcie *pcie) | ||
868 | { | ||
869 | const struct tegra_pcie_soc_data *soc = pcie->soc_data; | ||
870 | u32 value; | ||
871 | |||
872 | /* disable TX/RX data */ | ||
873 | value = pads_readl(pcie, PADS_CTL); | ||
874 | value &= ~(PADS_CTL_TX_DATA_EN_1L | PADS_CTL_RX_DATA_EN_1L); | ||
875 | pads_writel(pcie, value, PADS_CTL); | ||
876 | |||
877 | /* override IDDQ */ | ||
878 | value = pads_readl(pcie, PADS_CTL); | ||
879 | value |= PADS_CTL_IDDQ_1L; | ||
880 | pads_writel(pcie, PADS_CTL, value); | ||
881 | |||
882 | /* reset PLL */ | ||
883 | value = pads_readl(pcie, soc->pads_pll_ctl); | ||
884 | value &= ~PADS_PLL_CTL_RST_B4SM; | ||
885 | pads_writel(pcie, value, soc->pads_pll_ctl); | ||
886 | |||
887 | usleep_range(20, 100); | ||
888 | |||
889 | return 0; | ||
890 | } | ||
891 | |||
892 | static int tegra_pcie_port_phy_power_on(struct tegra_pcie_port *port) | ||
893 | { | ||
894 | struct device *dev = port->pcie->dev; | ||
895 | unsigned int i; | ||
896 | int err; | ||
897 | |||
898 | for (i = 0; i < port->lanes; i++) { | ||
899 | err = phy_power_on(port->phys[i]); | ||
900 | if (err < 0) { | ||
901 | dev_err(dev, "failed to power on PHY#%u: %d\n", i, | ||
902 | err); | ||
903 | return err; | ||
904 | } | ||
905 | } | ||
906 | |||
907 | return 0; | ||
908 | } | ||
909 | |||
910 | static int tegra_pcie_port_phy_power_off(struct tegra_pcie_port *port) | ||
911 | { | ||
912 | struct device *dev = port->pcie->dev; | ||
913 | unsigned int i; | ||
914 | int err; | ||
915 | |||
916 | for (i = 0; i < port->lanes; i++) { | ||
917 | err = phy_power_off(port->phys[i]); | ||
918 | if (err < 0) { | ||
919 | dev_err(dev, "failed to power off PHY#%u: %d\n", i, | ||
920 | err); | ||
921 | return err; | ||
922 | } | ||
923 | } | ||
924 | |||
925 | return 0; | ||
926 | } | ||
927 | |||
928 | static int tegra_pcie_phy_power_on(struct tegra_pcie *pcie) | ||
929 | { | ||
930 | struct tegra_pcie_port *port; | ||
931 | int err; | ||
932 | |||
933 | if (pcie->legacy_phy) { | ||
934 | if (pcie->phy) | ||
935 | err = phy_power_on(pcie->phy); | ||
936 | else | ||
937 | err = tegra_pcie_phy_enable(pcie); | ||
938 | |||
939 | if (err < 0) | ||
940 | dev_err(pcie->dev, "failed to power on PHY: %d\n", err); | ||
941 | |||
942 | return err; | ||
943 | } | ||
944 | |||
945 | list_for_each_entry(port, &pcie->ports, list) { | ||
946 | err = tegra_pcie_port_phy_power_on(port); | ||
947 | if (err < 0) { | ||
948 | dev_err(pcie->dev, | ||
949 | "failed to power on PCIe port %u PHY: %d\n", | ||
950 | port->index, err); | ||
951 | return err; | ||
952 | } | ||
953 | } | ||
954 | |||
955 | return 0; | ||
956 | } | ||
957 | |||
958 | static int tegra_pcie_phy_power_off(struct tegra_pcie *pcie) | ||
959 | { | ||
960 | struct tegra_pcie_port *port; | ||
961 | int err; | ||
962 | |||
963 | if (pcie->legacy_phy) { | ||
964 | if (pcie->phy) | ||
965 | err = phy_power_off(pcie->phy); | ||
966 | else | ||
967 | err = tegra_pcie_phy_disable(pcie); | ||
968 | |||
969 | if (err < 0) | ||
970 | dev_err(pcie->dev, "failed to power off PHY: %d\n", | ||
971 | err); | ||
972 | |||
973 | return err; | ||
974 | } | ||
975 | |||
976 | list_for_each_entry(port, &pcie->ports, list) { | ||
977 | err = tegra_pcie_port_phy_power_off(port); | ||
978 | if (err < 0) { | ||
979 | dev_err(pcie->dev, | ||
980 | "failed to power off PCIe port %u PHY: %d\n", | ||
981 | port->index, err); | ||
982 | return err; | ||
983 | } | ||
984 | } | ||
985 | |||
986 | return 0; | ||
987 | } | ||
988 | |||
863 | static int tegra_pcie_enable_controller(struct tegra_pcie *pcie) | 989 | static int tegra_pcie_enable_controller(struct tegra_pcie *pcie) |
864 | { | 990 | { |
865 | const struct tegra_pcie_soc_data *soc = pcie->soc_data; | 991 | const struct tegra_pcie_soc_data *soc = pcie->soc_data; |
@@ -899,13 +1025,9 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie) | |||
899 | afi_writel(pcie, value, AFI_FUSE); | 1025 | afi_writel(pcie, value, AFI_FUSE); |
900 | } | 1026 | } |
901 | 1027 | ||
902 | if (!pcie->phy) | 1028 | err = tegra_pcie_phy_power_on(pcie); |
903 | err = tegra_pcie_phy_enable(pcie); | ||
904 | else | ||
905 | err = phy_power_on(pcie->phy); | ||
906 | |||
907 | if (err < 0) { | 1029 | if (err < 0) { |
908 | dev_err(pcie->dev, "failed to power on PHY: %d\n", err); | 1030 | dev_err(pcie->dev, "failed to power on PHY(s): %d\n", err); |
909 | return err; | 1031 | return err; |
910 | } | 1032 | } |
911 | 1033 | ||
@@ -942,9 +1064,9 @@ static void tegra_pcie_power_off(struct tegra_pcie *pcie) | |||
942 | 1064 | ||
943 | /* TODO: disable and unprepare clocks? */ | 1065 | /* TODO: disable and unprepare clocks? */ |
944 | 1066 | ||
945 | err = phy_power_off(pcie->phy); | 1067 | err = tegra_pcie_phy_power_off(pcie); |
946 | if (err < 0) | 1068 | if (err < 0) |
947 | dev_warn(pcie->dev, "failed to power off PHY: %d\n", err); | 1069 | dev_err(pcie->dev, "failed to power off PHY(s): %d\n", err); |
948 | 1070 | ||
949 | reset_control_assert(pcie->pcie_xrst); | 1071 | reset_control_assert(pcie->pcie_xrst); |
950 | reset_control_assert(pcie->afi_rst); | 1072 | reset_control_assert(pcie->afi_rst); |
@@ -1049,6 +1171,100 @@ static int tegra_pcie_resets_get(struct tegra_pcie *pcie) | |||
1049 | return 0; | 1171 | return 0; |
1050 | } | 1172 | } |
1051 | 1173 | ||
1174 | static int tegra_pcie_phys_get_legacy(struct tegra_pcie *pcie) | ||
1175 | { | ||
1176 | int err; | ||
1177 | |||
1178 | pcie->phy = devm_phy_optional_get(pcie->dev, "pcie"); | ||
1179 | if (IS_ERR(pcie->phy)) { | ||
1180 | err = PTR_ERR(pcie->phy); | ||
1181 | dev_err(pcie->dev, "failed to get PHY: %d\n", err); | ||
1182 | return err; | ||
1183 | } | ||
1184 | |||
1185 | err = phy_init(pcie->phy); | ||
1186 | if (err < 0) { | ||
1187 | dev_err(pcie->dev, "failed to initialize PHY: %d\n", err); | ||
1188 | return err; | ||
1189 | } | ||
1190 | |||
1191 | pcie->legacy_phy = true; | ||
1192 | |||
1193 | return 0; | ||
1194 | } | ||
1195 | |||
1196 | static struct phy *devm_of_phy_optional_get_index(struct device *dev, | ||
1197 | struct device_node *np, | ||
1198 | const char *consumer, | ||
1199 | unsigned int index) | ||
1200 | { | ||
1201 | struct phy *phy; | ||
1202 | char *name; | ||
1203 | |||
1204 | name = kasprintf(GFP_KERNEL, "%s-%u", consumer, index); | ||
1205 | if (!name) | ||
1206 | return ERR_PTR(-ENOMEM); | ||
1207 | |||
1208 | phy = devm_of_phy_get(dev, np, name); | ||
1209 | kfree(name); | ||
1210 | |||
1211 | if (IS_ERR(phy) && PTR_ERR(phy) == -ENODEV) | ||
1212 | phy = NULL; | ||
1213 | |||
1214 | return phy; | ||
1215 | } | ||
1216 | |||
1217 | static int tegra_pcie_port_get_phys(struct tegra_pcie_port *port) | ||
1218 | { | ||
1219 | struct device *dev = port->pcie->dev; | ||
1220 | struct phy *phy; | ||
1221 | unsigned int i; | ||
1222 | int err; | ||
1223 | |||
1224 | port->phys = devm_kcalloc(dev, sizeof(phy), port->lanes, GFP_KERNEL); | ||
1225 | if (!port->phys) | ||
1226 | return -ENOMEM; | ||
1227 | |||
1228 | for (i = 0; i < port->lanes; i++) { | ||
1229 | phy = devm_of_phy_optional_get_index(dev, port->np, "pcie", i); | ||
1230 | if (IS_ERR(phy)) { | ||
1231 | dev_err(dev, "failed to get PHY#%u: %ld\n", i, | ||
1232 | PTR_ERR(phy)); | ||
1233 | return PTR_ERR(phy); | ||
1234 | } | ||
1235 | |||
1236 | err = phy_init(phy); | ||
1237 | if (err < 0) { | ||
1238 | dev_err(dev, "failed to initialize PHY#%u: %d\n", i, | ||
1239 | err); | ||
1240 | return err; | ||
1241 | } | ||
1242 | |||
1243 | port->phys[i] = phy; | ||
1244 | } | ||
1245 | |||
1246 | return 0; | ||
1247 | } | ||
1248 | |||
1249 | static int tegra_pcie_phys_get(struct tegra_pcie *pcie) | ||
1250 | { | ||
1251 | const struct tegra_pcie_soc_data *soc = pcie->soc_data; | ||
1252 | struct device_node *np = pcie->dev->of_node; | ||
1253 | struct tegra_pcie_port *port; | ||
1254 | int err; | ||
1255 | |||
1256 | if (!soc->has_gen2 || of_find_property(np, "phys", NULL) != NULL) | ||
1257 | return tegra_pcie_phys_get_legacy(pcie); | ||
1258 | |||
1259 | list_for_each_entry(port, &pcie->ports, list) { | ||
1260 | err = tegra_pcie_port_get_phys(port); | ||
1261 | if (err < 0) | ||
1262 | return err; | ||
1263 | } | ||
1264 | |||
1265 | return 0; | ||
1266 | } | ||
1267 | |||
1052 | static int tegra_pcie_get_resources(struct tegra_pcie *pcie) | 1268 | static int tegra_pcie_get_resources(struct tegra_pcie *pcie) |
1053 | { | 1269 | { |
1054 | struct platform_device *pdev = to_platform_device(pcie->dev); | 1270 | struct platform_device *pdev = to_platform_device(pcie->dev); |
@@ -1067,16 +1283,9 @@ static int tegra_pcie_get_resources(struct tegra_pcie *pcie) | |||
1067 | return err; | 1283 | return err; |
1068 | } | 1284 | } |
1069 | 1285 | ||
1070 | pcie->phy = devm_phy_optional_get(pcie->dev, "pcie"); | 1286 | err = tegra_pcie_phys_get(pcie); |
1071 | if (IS_ERR(pcie->phy)) { | ||
1072 | err = PTR_ERR(pcie->phy); | ||
1073 | dev_err(&pdev->dev, "failed to get PHY: %d\n", err); | ||
1074 | return err; | ||
1075 | } | ||
1076 | |||
1077 | err = phy_init(pcie->phy); | ||
1078 | if (err < 0) { | 1287 | if (err < 0) { |
1079 | dev_err(&pdev->dev, "failed to initialize PHY: %d\n", err); | 1288 | dev_err(&pdev->dev, "failed to get PHYs: %d\n", err); |
1080 | return err; | 1289 | return err; |
1081 | } | 1290 | } |
1082 | 1291 | ||
@@ -1752,6 +1961,7 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie) | |||
1752 | rp->index = index; | 1961 | rp->index = index; |
1753 | rp->lanes = value; | 1962 | rp->lanes = value; |
1754 | rp->pcie = pcie; | 1963 | rp->pcie = pcie; |
1964 | rp->np = port; | ||
1755 | 1965 | ||
1756 | rp->base = devm_ioremap_resource(pcie->dev, &rp->regs); | 1966 | rp->base = devm_ioremap_resource(pcie->dev, &rp->regs); |
1757 | if (IS_ERR(rp->base)) | 1967 | if (IS_ERR(rp->base)) |