]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
PCI: qcom: Handle mixed PERST#/PHY DT configuration
authorQiang Yu <qiang.yu@oss.qualcomm.com>
Fri, 8 May 2026 09:54:19 +0000 (02:54 -0700)
committerManivannan Sadhasivam <mani@kernel.org>
Tue, 26 May 2026 14:40:46 +0000 (20:10 +0530)
The driver currently supports two PERST# and PHY DT configurations. In one
case, PHY and PERST# are described in the RC node. In the other case, they
are described in the RP node.

A mixed setup is not supported. One common example is PHY on the RP node
while PERST# remains on the RC node. In that case the driver goes through
the RP parse path, does not find PERST# on RP, and does not report an error
because PERST# is optional. Probe can then succeed silently while PERST# is
left uncontrolled, and PCIe endpoints fail to work later. This silent
probe success makes debugging difficult.

Handle this mixed case in the RP parse path by checking whether PERST# is
present on RC and, if so, using the RC PERST# GPIO for RP ports while
keeping RP parsing for PHY. Emit a warning to indicate mixed DT content so
it can be fixed.

This keeps mixed systems functional and makes the configuration issue
visible instead of failing later at endpoint bring-up.

Suggested-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com>
Signed-off-by: Qiang Yu <qiang.yu@oss.qualcomm.com>
[mani: folded the fix: https://lore.kernel.org/linux-pci/20260526-fix_perst_gpio_handling-v1-1-9170507bb4e9@oss.qualcomm.com]
Signed-off-by: Manivannan Sadhasivam <mani@kernel.org>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Link: https://patch.msgid.link/20260508-mix_perst_phy_dts-v1-1-9eff6ee9b51a@oss.qualcomm.com
drivers/pci/controller/dwc/pcie-qcom.c

index bc5a31efc0d071e1105be27038bfdb1960968aae..9173369cca8777ee696838b47506a9e3da26cb1b 100644 (file)
@@ -289,6 +289,7 @@ struct qcom_pcie {
        const struct qcom_pcie_cfg *cfg;
        struct dentry *debugfs;
        struct list_head ports;
+       struct gpio_desc *reset;
        bool use_pm_opp;
 };
 
@@ -1798,6 +1799,13 @@ static int qcom_pcie_parse_perst(struct qcom_pcie *pcie,
        struct gpio_desc *reset;
        int ret;
 
+       if (pcie->reset) {
+               dev_warn_once(dev,
+                             "Reusing PERST# from Root Complex node. DT needs to be fixed!\n");
+               reset = pcie->reset;
+               goto skip_perst_parsing;
+       }
+
        if (!of_find_property(np, "reset-gpios", NULL))
                goto parse_child_node;
 
@@ -1816,6 +1824,7 @@ static int qcom_pcie_parse_perst(struct qcom_pcie *pcie,
                return PTR_ERR(reset);
        }
 
+skip_perst_parsing:
        perst = devm_kzalloc(dev, sizeof(*perst), GFP_KERNEL);
        if (!perst)
                return -ENOMEM;
@@ -1873,6 +1882,13 @@ static int qcom_pcie_parse_ports(struct qcom_pcie *pcie)
        struct device *dev = pcie->pci->dev;
        int ret = -ENODEV;
 
+       if (of_find_property(dev->of_node, "perst-gpios", NULL)) {
+               pcie->reset = devm_gpiod_get_optional(dev, "perst",
+                                                     GPIOD_OUT_HIGH);
+               if (IS_ERR(pcie->reset))
+                       return PTR_ERR(pcie->reset);
+       }
+
        for_each_available_child_of_node_scoped(dev->of_node, of_port) {
                if (!of_node_is_type(of_port, "pci"))
                        continue;
@@ -1899,7 +1915,6 @@ static int qcom_pcie_parse_legacy_binding(struct qcom_pcie *pcie)
        struct device *dev = pcie->pci->dev;
        struct qcom_pcie_perst *perst;
        struct qcom_pcie_port *port;
-       struct gpio_desc *reset;
        struct phy *phy;
        int ret;
 
@@ -1907,10 +1922,6 @@ static int qcom_pcie_parse_legacy_binding(struct qcom_pcie *pcie)
        if (IS_ERR(phy))
                return PTR_ERR(phy);
 
-       reset = devm_gpiod_get_optional(dev, "perst", GPIOD_OUT_HIGH);
-       if (IS_ERR(reset))
-               return PTR_ERR(reset);
-
        ret = phy_init(phy);
        if (ret)
                return ret;
@@ -1927,7 +1938,7 @@ static int qcom_pcie_parse_legacy_binding(struct qcom_pcie *pcie)
        INIT_LIST_HEAD(&port->list);
        list_add_tail(&port->list, &pcie->ports);
 
-       perst->desc = reset;
+       perst->desc = pcie->reset;
        INIT_LIST_HEAD(&port->perst);
        INIT_LIST_HEAD(&perst->list);
        list_add_tail(&perst->list, &port->perst);