]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
PCI: amd-mdb: Add support for PCIe RP PERST# signal handling
authorSai Krishna Musham <sai.krishna.musham@amd.com>
Thu, 7 Aug 2025 07:40:19 +0000 (13:10 +0530)
committerManivannan Sadhasivam <mani@kernel.org>
Mon, 11 Aug 2025 10:39:45 +0000 (16:09 +0530)
Add support for handling the AMD Versal Gen 2 MDB PCIe Root Port PERST#
signal via a GPIO by parsing the new PCIe bridge node to acquire the
reset GPIO. If the bridge node is not found, fall back to acquiring it
from the PCIe host bridge node.

As part of this, update the interrupt controller node parsing to use
of_get_child_by_name() instead of of_get_next_child(), since the PCIe
host bridge node now has multiple children. This ensures the correct
node is selected during initialization.

Signed-off-by: Sai Krishna Musham <sai.krishna.musham@amd.com>
Signed-off-by: Manivannan Sadhasivam <mani@kernel.org>
Link: https://patch.msgid.link/20250807074019.811672-3-sai.krishna.musham@amd.com
drivers/pci/controller/dwc/pcie-amd-mdb.c

index 9f7251a16d32122ee617777ce2eafad93672d95c..3c6e837465bb7bf97bfe2a0471d396f9ebfb0e04 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/resource.h>
 #include <linux/types.h>
 
+#include "../../pci.h"
 #include "pcie-designware.h"
 
 #define AMD_MDB_TLP_IR_STATUS_MISC             0x4C0
@@ -56,6 +57,7 @@
  * @slcr: MDB System Level Control and Status Register (SLCR) base
  * @intx_domain: INTx IRQ domain pointer
  * @mdb_domain: MDB IRQ domain pointer
+ * @perst_gpio: GPIO descriptor for PERST# signal handling
  * @intx_irq: INTx IRQ interrupt number
  */
 struct amd_mdb_pcie {
@@ -63,6 +65,7 @@ struct amd_mdb_pcie {
        void __iomem                    *slcr;
        struct irq_domain               *intx_domain;
        struct irq_domain               *mdb_domain;
+       struct gpio_desc                *perst_gpio;
        int                             intx_irq;
 };
 
@@ -284,7 +287,7 @@ static int amd_mdb_pcie_init_irq_domains(struct amd_mdb_pcie *pcie,
        struct device_node *pcie_intc_node;
        int err;
 
-       pcie_intc_node = of_get_next_child(node, NULL);
+       pcie_intc_node = of_get_child_by_name(node, "interrupt-controller");
        if (!pcie_intc_node) {
                dev_err(dev, "No PCIe Intc node found\n");
                return -ENODEV;
@@ -402,6 +405,28 @@ static int amd_mdb_setup_irq(struct amd_mdb_pcie *pcie,
        return 0;
 }
 
+static int amd_mdb_parse_pcie_port(struct amd_mdb_pcie *pcie)
+{
+       struct device *dev = pcie->pci.dev;
+       struct device_node *pcie_port_node __maybe_unused;
+
+       /*
+        * This platform currently supports only one Root Port, so the loop
+        * will execute only once.
+        * TODO: Enhance the driver to handle multiple Root Ports in the future.
+        */
+       for_each_child_of_node_with_prefix(dev->of_node, pcie_port_node, "pcie") {
+               pcie->perst_gpio = devm_fwnode_gpiod_get(dev, of_fwnode_handle(pcie_port_node),
+                                                        "reset", GPIOD_OUT_HIGH, NULL);
+               if (IS_ERR(pcie->perst_gpio))
+                       return dev_err_probe(dev, PTR_ERR(pcie->perst_gpio),
+                                            "Failed to request reset GPIO\n");
+               return 0;
+       }
+
+       return -ENODEV;
+}
+
 static int amd_mdb_add_pcie_port(struct amd_mdb_pcie *pcie,
                                 struct platform_device *pdev)
 {
@@ -426,6 +451,12 @@ static int amd_mdb_add_pcie_port(struct amd_mdb_pcie *pcie,
 
        pp->ops = &amd_mdb_pcie_host_ops;
 
+       if (pcie->perst_gpio) {
+               mdelay(PCIE_T_PVPERL_MS);
+               gpiod_set_value_cansleep(pcie->perst_gpio, 0);
+               mdelay(PCIE_RESET_CONFIG_WAIT_MS);
+       }
+
        err = dw_pcie_host_init(pp);
        if (err) {
                dev_err(dev, "Failed to initialize host, err=%d\n", err);
@@ -444,6 +475,7 @@ static int amd_mdb_pcie_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct amd_mdb_pcie *pcie;
        struct dw_pcie *pci;
+       int ret;
 
        pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
        if (!pcie)
@@ -454,6 +486,24 @@ static int amd_mdb_pcie_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, pcie);
 
+       ret = amd_mdb_parse_pcie_port(pcie);
+       /*
+        * If amd_mdb_parse_pcie_port returns -ENODEV, it indicates that the
+        * PCIe Bridge node was not found in the device tree. This is not
+        * considered a fatal error and will trigger a fallback where the
+        * reset GPIO is acquired directly from the PCIe Host Bridge node.
+        */
+       if (ret) {
+               if (ret != -ENODEV)
+                       return ret;
+
+               pcie->perst_gpio = devm_gpiod_get_optional(dev, "reset",
+                                                          GPIOD_OUT_HIGH);
+               if (IS_ERR(pcie->perst_gpio))
+                       return dev_err_probe(dev, PTR_ERR(pcie->perst_gpio),
+                                            "Failed to request reset GPIO\n");
+       }
+
        return amd_mdb_add_pcie_port(pcie, pdev);
 }