Skip to content

Commit 6fe7c18

Browse files
committed
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 <[email protected]> Acked-by: Bjorn Helgaas <[email protected]> Signed-off-by: Thierry Reding <[email protected]>
1 parent 13541cc commit 6fe7c18

File tree

1 file changed

+227
-17
lines changed

1 file changed

+227
-17
lines changed

drivers/pci/host/pci-tegra.c

Lines changed: 227 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@ struct tegra_pcie {
295295
struct reset_control *afi_rst;
296296
struct reset_control *pcie_xrst;
297297

298+
bool legacy_phy;
298299
struct phy *phy;
299300

300301
struct tegra_msi msi;
@@ -311,11 +312,14 @@ struct tegra_pcie {
311312

312313
struct tegra_pcie_port {
313314
struct tegra_pcie *pcie;
315+
struct device_node *np;
314316
struct list_head list;
315317
struct resource regs;
316318
void __iomem *base;
317319
unsigned int index;
318320
unsigned int lanes;
321+
322+
struct phy **phys;
319323
};
320324

321325
struct tegra_pcie_bus {
@@ -860,6 +864,128 @@ static int tegra_pcie_phy_enable(struct tegra_pcie *pcie)
860864
return 0;
861865
}
862866

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+
863989
static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
864990
{
865991
const struct tegra_pcie_soc_data *soc = pcie->soc_data;
@@ -899,13 +1025,9 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
8991025
afi_writel(pcie, value, AFI_FUSE);
9001026
}
9011027

902-
if (!pcie->phy)
903-
err = tegra_pcie_phy_enable(pcie);
904-
else
905-
err = phy_power_on(pcie->phy);
906-
1028+
err = tegra_pcie_phy_power_on(pcie);
9071029
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);
9091031
return err;
9101032
}
9111033

@@ -942,9 +1064,9 @@ static void tegra_pcie_power_off(struct tegra_pcie *pcie)
9421064

9431065
/* TODO: disable and unprepare clocks? */
9441066

945-
err = phy_power_off(pcie->phy);
1067+
err = tegra_pcie_phy_power_off(pcie);
9461068
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);
9481070

9491071
reset_control_assert(pcie->pcie_xrst);
9501072
reset_control_assert(pcie->afi_rst);
@@ -1049,6 +1171,100 @@ static int tegra_pcie_resets_get(struct tegra_pcie *pcie)
10491171
return 0;
10501172
}
10511173

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+
10521268
static int tegra_pcie_get_resources(struct tegra_pcie *pcie)
10531269
{
10541270
struct platform_device *pdev = to_platform_device(pcie->dev);
@@ -1067,16 +1283,9 @@ static int tegra_pcie_get_resources(struct tegra_pcie *pcie)
10671283
return err;
10681284
}
10691285

1070-
pcie->phy = devm_phy_optional_get(pcie->dev, "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);
1286+
err = tegra_pcie_phys_get(pcie);
10781287
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);
10801289
return err;
10811290
}
10821291

@@ -1752,6 +1961,7 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie)
17521961
rp->index = index;
17531962
rp->lanes = value;
17541963
rp->pcie = pcie;
1964+
rp->np = port;
17551965

17561966
rp->base = devm_ioremap_resource(pcie->dev, &rp->regs);
17571967
if (IS_ERR(rp->base))

0 commit comments

Comments
 (0)