Skip to content

Commit a2fbecd

Browse files
PCI: qcom: Add support for parsing the new Root Port binding
The DT binding has moved the PHY, PERST# properties to Root Port node from the Host Bridge node. So add support for parsing the new binding. The new binding uses 'reset-gpios' property for PERST#, hence parse the same property in the driver instead of the legacy 'perst-gpios'. To maintain DT backwards compatibility, fallback to the legacy method of parsing the host bridge node if the properties are not present in the Root Port node. Signed-off-by: Krishna Chaitanya Chundru <[email protected]> [mani: refactored the root port parsing code, fixed a bug & commit message rewording] Signed-off-by: Manivannan Sadhasivam <[email protected]> Signed-off-by: Bjorn Helgaas <[email protected]> Link: https://patch.msgid.link/[email protected]
1 parent 38fcbfb commit a2fbecd

File tree

1 file changed

+176
-27
lines changed

1 file changed

+176
-27
lines changed

drivers/pci/controller/dwc/pcie-qcom.c

Lines changed: 176 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,12 @@ struct qcom_pcie_cfg {
267267
bool no_l0s;
268268
};
269269

270+
struct qcom_pcie_port {
271+
struct list_head list;
272+
struct gpio_desc *reset;
273+
struct phy *phy;
274+
};
275+
270276
struct qcom_pcie {
271277
struct dw_pcie *pci;
272278
void __iomem *parf; /* DT parf */
@@ -279,24 +285,37 @@ struct qcom_pcie {
279285
struct icc_path *icc_cpu;
280286
const struct qcom_pcie_cfg *cfg;
281287
struct dentry *debugfs;
288+
struct list_head ports;
282289
bool suspended;
283290
bool use_pm_opp;
284291
};
285292

286293
#define to_qcom_pcie(x) dev_get_drvdata((x)->dev)
287294

288-
static void qcom_ep_reset_assert(struct qcom_pcie *pcie)
295+
static void qcom_perst_assert(struct qcom_pcie *pcie, bool assert)
289296
{
290-
gpiod_set_value_cansleep(pcie->reset, 1);
297+
struct qcom_pcie_port *port;
298+
int val = assert ? 1 : 0;
299+
300+
if (list_empty(&pcie->ports))
301+
gpiod_set_value_cansleep(pcie->reset, val);
302+
else
303+
list_for_each_entry(port, &pcie->ports, list)
304+
gpiod_set_value_cansleep(port->reset, val);
305+
291306
usleep_range(PERST_DELAY_US, PERST_DELAY_US + 500);
292307
}
293308

309+
static void qcom_ep_reset_assert(struct qcom_pcie *pcie)
310+
{
311+
qcom_perst_assert(pcie, true);
312+
}
313+
294314
static void qcom_ep_reset_deassert(struct qcom_pcie *pcie)
295315
{
296316
/* Ensure that PERST has been asserted for at least 100 ms */
297317
msleep(PCIE_T_PVPERL_MS);
298-
gpiod_set_value_cansleep(pcie->reset, 0);
299-
usleep_range(PERST_DELAY_US, PERST_DELAY_US + 500);
318+
qcom_perst_assert(pcie, false);
300319
}
301320

302321
static int qcom_pcie_start_link(struct dw_pcie *pci)
@@ -1234,6 +1253,59 @@ static bool qcom_pcie_link_up(struct dw_pcie *pci)
12341253
return val & PCI_EXP_LNKSTA_DLLLA;
12351254
}
12361255

1256+
static void qcom_pcie_phy_exit(struct qcom_pcie *pcie)
1257+
{
1258+
struct qcom_pcie_port *port;
1259+
1260+
if (list_empty(&pcie->ports))
1261+
phy_exit(pcie->phy);
1262+
else
1263+
list_for_each_entry(port, &pcie->ports, list)
1264+
phy_exit(port->phy);
1265+
}
1266+
1267+
static void qcom_pcie_phy_power_off(struct qcom_pcie *pcie)
1268+
{
1269+
struct qcom_pcie_port *port;
1270+
1271+
if (list_empty(&pcie->ports)) {
1272+
phy_power_off(pcie->phy);
1273+
} else {
1274+
list_for_each_entry(port, &pcie->ports, list)
1275+
phy_power_off(port->phy);
1276+
}
1277+
}
1278+
1279+
static int qcom_pcie_phy_power_on(struct qcom_pcie *pcie)
1280+
{
1281+
struct qcom_pcie_port *port;
1282+
int ret = 0;
1283+
1284+
if (list_empty(&pcie->ports)) {
1285+
ret = phy_set_mode_ext(pcie->phy, PHY_MODE_PCIE, PHY_MODE_PCIE_RC);
1286+
if (ret)
1287+
return ret;
1288+
1289+
ret = phy_power_on(pcie->phy);
1290+
if (ret)
1291+
return ret;
1292+
} else {
1293+
list_for_each_entry(port, &pcie->ports, list) {
1294+
ret = phy_set_mode_ext(port->phy, PHY_MODE_PCIE, PHY_MODE_PCIE_RC);
1295+
if (ret)
1296+
return ret;
1297+
1298+
ret = phy_power_on(port->phy);
1299+
if (ret) {
1300+
qcom_pcie_phy_power_off(pcie);
1301+
return ret;
1302+
}
1303+
}
1304+
}
1305+
1306+
return ret;
1307+
}
1308+
12371309
static int qcom_pcie_host_init(struct dw_pcie_rp *pp)
12381310
{
12391311
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
@@ -1246,11 +1318,7 @@ static int qcom_pcie_host_init(struct dw_pcie_rp *pp)
12461318
if (ret)
12471319
return ret;
12481320

1249-
ret = phy_set_mode_ext(pcie->phy, PHY_MODE_PCIE, PHY_MODE_PCIE_RC);
1250-
if (ret)
1251-
goto err_deinit;
1252-
1253-
ret = phy_power_on(pcie->phy);
1321+
ret = qcom_pcie_phy_power_on(pcie);
12541322
if (ret)
12551323
goto err_deinit;
12561324

@@ -1273,7 +1341,7 @@ static int qcom_pcie_host_init(struct dw_pcie_rp *pp)
12731341
err_assert_reset:
12741342
qcom_ep_reset_assert(pcie);
12751343
err_disable_phy:
1276-
phy_power_off(pcie->phy);
1344+
qcom_pcie_phy_power_off(pcie);
12771345
err_deinit:
12781346
pcie->cfg->ops->deinit(pcie);
12791347

@@ -1286,7 +1354,7 @@ static void qcom_pcie_host_deinit(struct dw_pcie_rp *pp)
12861354
struct qcom_pcie *pcie = to_qcom_pcie(pci);
12871355

12881356
qcom_ep_reset_assert(pcie);
1289-
phy_power_off(pcie->phy);
1357+
qcom_pcie_phy_power_off(pcie);
12901358
pcie->cfg->ops->deinit(pcie);
12911359
}
12921360

@@ -1631,10 +1699,85 @@ static const struct pci_ecam_ops pci_qcom_ecam_ops = {
16311699
}
16321700
};
16331701

1702+
static int qcom_pcie_parse_port(struct qcom_pcie *pcie, struct device_node *node)
1703+
{
1704+
struct device *dev = pcie->pci->dev;
1705+
struct qcom_pcie_port *port;
1706+
struct gpio_desc *reset;
1707+
struct phy *phy;
1708+
int ret;
1709+
1710+
reset = devm_fwnode_gpiod_get(dev, of_fwnode_handle(node),
1711+
"reset", GPIOD_OUT_HIGH, "PERST#");
1712+
if (IS_ERR(reset))
1713+
return PTR_ERR(reset);
1714+
1715+
phy = devm_of_phy_get(dev, node, NULL);
1716+
if (IS_ERR(phy))
1717+
return PTR_ERR(phy);
1718+
1719+
port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
1720+
if (!port)
1721+
return -ENOMEM;
1722+
1723+
ret = phy_init(phy);
1724+
if (ret)
1725+
return ret;
1726+
1727+
port->reset = reset;
1728+
port->phy = phy;
1729+
INIT_LIST_HEAD(&port->list);
1730+
list_add_tail(&port->list, &pcie->ports);
1731+
1732+
return 0;
1733+
}
1734+
1735+
static int qcom_pcie_parse_ports(struct qcom_pcie *pcie)
1736+
{
1737+
struct device *dev = pcie->pci->dev;
1738+
struct qcom_pcie_port *port, *tmp;
1739+
int ret = -ENOENT;
1740+
1741+
for_each_available_child_of_node_scoped(dev->of_node, of_port) {
1742+
ret = qcom_pcie_parse_port(pcie, of_port);
1743+
if (ret)
1744+
goto err_port_del;
1745+
}
1746+
1747+
return ret;
1748+
1749+
err_port_del:
1750+
list_for_each_entry_safe(port, tmp, &pcie->ports, list)
1751+
list_del(&port->list);
1752+
1753+
return ret;
1754+
}
1755+
1756+
static int qcom_pcie_parse_legacy_binding(struct qcom_pcie *pcie)
1757+
{
1758+
struct device *dev = pcie->pci->dev;
1759+
int ret;
1760+
1761+
pcie->phy = devm_phy_optional_get(dev, "pciephy");
1762+
if (IS_ERR(pcie->phy))
1763+
return PTR_ERR(pcie->phy);
1764+
1765+
pcie->reset = devm_gpiod_get_optional(dev, "perst", GPIOD_OUT_HIGH);
1766+
if (IS_ERR(pcie->reset))
1767+
return PTR_ERR(pcie->reset);
1768+
1769+
ret = phy_init(pcie->phy);
1770+
if (ret)
1771+
return ret;
1772+
1773+
return 0;
1774+
}
1775+
16341776
static int qcom_pcie_probe(struct platform_device *pdev)
16351777
{
16361778
const struct qcom_pcie_cfg *pcie_cfg;
16371779
unsigned long max_freq = ULONG_MAX;
1780+
struct qcom_pcie_port *port, *tmp;
16381781
struct device *dev = &pdev->dev;
16391782
struct dev_pm_opp *opp;
16401783
struct qcom_pcie *pcie;
@@ -1701,6 +1844,8 @@ static int qcom_pcie_probe(struct platform_device *pdev)
17011844
goto err_pm_runtime_put;
17021845
}
17031846

1847+
INIT_LIST_HEAD(&pcie->ports);
1848+
17041849
pci->dev = dev;
17051850
pci->ops = &dw_pcie_ops;
17061851
pp = &pci->pp;
@@ -1709,12 +1854,6 @@ static int qcom_pcie_probe(struct platform_device *pdev)
17091854

17101855
pcie->cfg = pcie_cfg;
17111856

1712-
pcie->reset = devm_gpiod_get_optional(dev, "perst", GPIOD_OUT_HIGH);
1713-
if (IS_ERR(pcie->reset)) {
1714-
ret = PTR_ERR(pcie->reset);
1715-
goto err_pm_runtime_put;
1716-
}
1717-
17181857
pcie->parf = devm_platform_ioremap_resource_byname(pdev, "parf");
17191858
if (IS_ERR(pcie->parf)) {
17201859
ret = PTR_ERR(pcie->parf);
@@ -1737,12 +1876,6 @@ static int qcom_pcie_probe(struct platform_device *pdev)
17371876
}
17381877
}
17391878

1740-
pcie->phy = devm_phy_optional_get(dev, "pciephy");
1741-
if (IS_ERR(pcie->phy)) {
1742-
ret = PTR_ERR(pcie->phy);
1743-
goto err_pm_runtime_put;
1744-
}
1745-
17461879
/* OPP table is optional */
17471880
ret = devm_pm_opp_of_add_table(dev);
17481881
if (ret && ret != -ENODEV) {
@@ -1789,9 +1922,23 @@ static int qcom_pcie_probe(struct platform_device *pdev)
17891922

17901923
pp->ops = &qcom_pcie_dw_ops;
17911924

1792-
ret = phy_init(pcie->phy);
1793-
if (ret)
1794-
goto err_pm_runtime_put;
1925+
ret = qcom_pcie_parse_ports(pcie);
1926+
if (ret) {
1927+
if (ret != -ENOENT) {
1928+
dev_err_probe(pci->dev, ret,
1929+
"Failed to parse Root Port: %d\n", ret);
1930+
goto err_pm_runtime_put;
1931+
}
1932+
1933+
/*
1934+
* In the case of properties not populated in Root Port node,
1935+
* fallback to the legacy method of parsing the Host Bridge
1936+
* node. This is to maintain DT backwards compatibility.
1937+
*/
1938+
ret = qcom_pcie_parse_legacy_binding(pcie);
1939+
if (ret)
1940+
goto err_pm_runtime_put;
1941+
}
17951942

17961943
platform_set_drvdata(pdev, pcie);
17971944

@@ -1836,7 +1983,9 @@ static int qcom_pcie_probe(struct platform_device *pdev)
18361983
err_host_deinit:
18371984
dw_pcie_host_deinit(pp);
18381985
err_phy_exit:
1839-
phy_exit(pcie->phy);
1986+
qcom_pcie_phy_exit(pcie);
1987+
list_for_each_entry_safe(port, tmp, &pcie->ports, list)
1988+
list_del(&port->list);
18401989
err_pm_runtime_put:
18411990
pm_runtime_put(dev);
18421991
pm_runtime_disable(dev);

0 commit comments

Comments
 (0)