Since the Qcom platforms rely on pwrctrl framework to control the power supplies, allow it to control PERST# also. PERST# should be toggled during the power-on and power-off scenarios. But the controller driver still need to assert PERST# during the controller initialization. So only skip the deassert if pwrctrl usage is detected. The pwrctrl framework will deassert PERST# after turning on the supplies. The usage of pwrctrl framework is detected based on the new DT binding i.e., with the presence of PERST# and PHY properties in the Root Port node instead of the host bridge node. When the legacy binding is used, PERST# is only controlled by the controller driver since it is not reliable to detect whether pwrctrl is used or not. So the legacy platforms are untouched by this commit. Signed-off-by: Manivannan Sadhasivam <mani@xxxxxxxxxx> --- drivers/pci/controller/dwc/pcie-designware-host.c | 1 + drivers/pci/controller/dwc/pcie-designware.h | 1 + drivers/pci/controller/dwc/pcie-qcom.c | 26 ++++++++++++++++++++++- 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index af6c91ec7312bab6c6e5ad35b051d0f452fe7b8d..e45f53bb135a75963318666a479eb6d9582f30eb 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -492,6 +492,7 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp) return -ENOMEM; pp->bridge = bridge; + bridge->perst = pp->perst; ret = dw_pcie_host_get_resources(pp); if (ret) diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 4165c49a0a5059cab92dee3c47f8024af9d840bd..7b28f76ebf6a2de8781746eba43a8e3ad9a5cbb2 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -430,6 +430,7 @@ struct dw_pcie_rp { struct resource *msg_res; bool use_linkup_irq; struct pci_eq_presets presets; + struct gpio_desc **perst; }; struct dw_pcie_ep_ops { diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c index 620ac7cf09472b84c37e83ee3ce40e94a1d9d878..61e1d0d6469030c549328ab4d8c65d5377d525e3 100644 --- a/drivers/pci/controller/dwc/pcie-qcom.c +++ b/drivers/pci/controller/dwc/pcie-qcom.c @@ -313,6 +313,11 @@ static void qcom_ep_reset_assert(struct qcom_pcie *pcie) static void qcom_ep_reset_deassert(struct qcom_pcie *pcie) { + struct dw_pcie_rp *pp = &pcie->pci->pp; + + if (pp->perst) + return; + /* Ensure that PERST has been asserted for at least 100 ms */ msleep(PCIE_T_PVPERL_MS); qcom_perst_assert(pcie, false); @@ -1701,11 +1706,12 @@ static const struct pci_ecam_ops pci_qcom_ecam_ops = { static int qcom_pcie_parse_port(struct qcom_pcie *pcie, struct device_node *node) { + struct dw_pcie_rp *pp = &pcie->pci->pp; struct device *dev = pcie->pci->dev; struct qcom_pcie_port *port; struct gpio_desc *reset; struct phy *phy; - int ret; + int ret, devfn; reset = devm_fwnode_gpiod_get(dev, of_fwnode_handle(node), "reset", GPIOD_OUT_HIGH, "PERST#"); @@ -1724,6 +1730,12 @@ static int qcom_pcie_parse_port(struct qcom_pcie *pcie, struct device_node *node if (ret) return ret; + devfn = of_pci_get_devfn(node); + if (devfn < 0) + return -ENOENT; + + pp->perst[PCI_SLOT(devfn)] = reset; + port->reset = reset; port->phy = phy; INIT_LIST_HEAD(&port->list); @@ -1734,10 +1746,20 @@ static int qcom_pcie_parse_port(struct qcom_pcie *pcie, struct device_node *node static int qcom_pcie_parse_ports(struct qcom_pcie *pcie) { + struct dw_pcie_rp *pp = &pcie->pci->pp; struct device *dev = pcie->pci->dev; struct qcom_pcie_port *port, *tmp; + int child_cnt; int ret = -ENOENT; + child_cnt = of_get_available_child_count(dev->of_node); + if (!child_cnt) + return ret; + + pp->perst = kcalloc(child_cnt, sizeof(struct gpio_desc *), GFP_KERNEL); + if (!pp->perst) + return -ENOMEM; + for_each_available_child_of_node_scoped(dev->of_node, of_port) { ret = qcom_pcie_parse_port(pcie, of_port); if (ret) @@ -1747,6 +1769,7 @@ static int qcom_pcie_parse_ports(struct qcom_pcie *pcie) return ret; err_port_del: + kfree(pp->perst); list_for_each_entry_safe(port, tmp, &pcie->ports, list) list_del(&port->list); @@ -1984,6 +2007,7 @@ static int qcom_pcie_probe(struct platform_device *pdev) dw_pcie_host_deinit(pp); err_phy_exit: qcom_pcie_phy_exit(pcie); + kfree(pp->perst); list_for_each_entry_safe(port, tmp, &pcie->ports, list) list_del(&port->list); err_pm_runtime_put: -- 2.45.2