From: Sai Krishna Musham <sai.krishna.musham@amd.com>
To: <bhelgaas@google.com>, <lpieralisi@kernel.org>, <kw@linux.com>,
<mani@kernel.org>, <robh@kernel.org>, <krzk+dt@kernel.org>,
<conor+dt@kernel.org>, <cassel@kernel.org>
Cc: <linux-pci@vger.kernel.org>, <devicetree@vger.kernel.org>,
<linux-kernel@vger.kernel.org>, <michal.simek@amd.com>,
<bharat.kumar.gogada@amd.com>, <thippeswamy.havalige@amd.com>,
<sai.krishna.musham@amd.com>
Subject: [PATCH v8 2/2] PCI: xilinx-cpm: Add support for PCIe RP PERST# signal
Date: Fri, 7 Aug 2026 18:05:07 +0530 [thread overview]
Message-ID: <20260807123507.3418671-3-sai.krishna.musham@amd.com> (raw)
In-Reply-To: <20260807123507.3418671-1-sai.krishna.musham@amd.com>
Add support for the PCIe Root Port PERST# signal using the GPIO
framework, along with the PCIe IP reset. This reset is managed
by the driver and occurs after the Initial Power Up sequence
(PCIe CEM r6.0, 2.2.1) is handled in hardware before the driver's
probe function is called.
This is useful in warm reset scenarios where the power rails stay stable
and only PERST# is toggled. Applying both the IP reset and PERST# resets
the Root Port controller and Endpoint synchronously, improving
reliability and avoiding lane errors.
Both the reset GPIO and the reset controller are optional to keep
backward compatibility with existing DTBs. Also add a PCIE_T_PERST_US
(100 us) macro in pci.h for the PERST# active time (PCIe CEM r6.0,
sec 2.11.2, "T_PERST").
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>
---
Changes in v8:
- Use resets framework for handling PCIe IP reset.
- Update source to parse reset-gpios from child node.
- Update PCIE_T_PERST_US macro in pci.h
- Remove PERST# support for CPM5NC.
v1: https://lore.kernel.org/all/20250224063046.1438006-3-sai.krishna.musham@amd.com/
v2: https://lore.kernel.org/all/20250226124358.88227-3-sai.krishna.musham@amd.com/
v3: https://lore.kernel.org/all/20250227042454.907182-3-sai.krishna.musham@amd.com/
v4: https://lore.kernel.org/all/20250318092648.2298280-3-sai.krishna.musham@amd.com/
v5: https://lore.kernel.org/all/20250321114211.2185782-3-sai.krishna.musham@amd.com/
v6: https://lore.kernel.org/all/20250326022811.3090688-3-sai.krishna.musham@amd.com/
v7: https://lore.kernel.org/all/20250414032304.862779-3-sai.krishna.musham@amd.com/
---
drivers/pci/controller/pcie-xilinx-cpm.c | 78 +++++++++++++++++++++++-
drivers/pci/pci.h | 9 +++
2 files changed, 86 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/controller/pcie-xilinx-cpm.c b/drivers/pci/controller/pcie-xilinx-cpm.c
index d38f27e20761..040d37643991 100644
--- a/drivers/pci/controller/pcie-xilinx-cpm.c
+++ b/drivers/pci/controller/pcie-xilinx-cpm.c
@@ -6,6 +6,8 @@
*/
#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqchip.h>
@@ -16,6 +18,7 @@
#include <linux/of_address.h>
#include <linux/of_pci.h>
#include <linux/of_platform.h>
+#include <linux/reset.h>
#include "../pci.h"
#include "pcie-xilinx-common.h"
@@ -113,6 +116,8 @@ struct xilinx_cpm_variant {
* @irq: Error interrupt number
* @lock: lock protecting shared register access
* @variant: CPM version check pointer
+ * @perst_gpio: GPIO descriptor for PERST# signal handling
+ * @rstc: Pointer to the PCIe controller reset
*/
struct xilinx_cpm_pcie {
struct device *dev;
@@ -125,6 +130,8 @@ struct xilinx_cpm_pcie {
int irq;
raw_spinlock_t lock;
const struct xilinx_cpm_variant *variant;
+ struct gpio_desc *perst_gpio;
+ struct reset_control *rstc;
};
static u32 pcie_read(struct xilinx_cpm_pcie *port, u32 reg)
@@ -389,7 +396,7 @@ static int xilinx_cpm_pcie_init_irq_domain(struct xilinx_cpm_pcie *port)
struct device_node *pcie_intc_node;
/* Setup INTx */
- 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 -EINVAL;
@@ -469,6 +476,22 @@ static int xilinx_cpm_setup_irq(struct xilinx_cpm_pcie *port)
return 0;
}
+/**
+ * xilinx_cpm_pcie_reset - Reset the PCIe controller and deassert PERST#
+ * @port: PCIe port information
+ *
+ * Reset the PCIe controller and then release the PERST# signal so that the
+ * link can train once the bridge is enabled.
+ */
+static void xilinx_cpm_pcie_reset(struct xilinx_cpm_pcie *port)
+{
+ reset_control_assert(port->rstc);
+ udelay(PCIE_T_PERST_US);
+ reset_control_deassert(port->rstc);
+ gpiod_set_value_cansleep(port->perst_gpio, 0);
+ mdelay(PCIE_RESET_CONFIG_WAIT_MS);
+}
+
/**
* xilinx_cpm_pcie_init_port - Initialize hardware
* @port: PCIe port information
@@ -480,6 +503,9 @@ static void xilinx_cpm_pcie_init_port(struct xilinx_cpm_pcie *port)
if (variant->version == CPM5NC_HOST)
return;
+ if (port->perst_gpio && port->rstc)
+ xilinx_cpm_pcie_reset(port);
+
if (cpm_pcie_link_up(port))
dev_info(port->dev, "PCIe Link is UP\n");
else
@@ -512,6 +538,43 @@ static void xilinx_cpm_pcie_init_port(struct xilinx_cpm_pcie *port)
XILINX_CPM_PCIE_REG_RPSC);
}
+/**
+ * xilinx_cpm_pcie_parse_port - Parse the PCIe Root Port child node
+ * @port: PCIe port information
+ *
+ * Read the PERST# GPIO from the Root Port child node.
+ *
+ * Return: '0' on success and error value on failure
+ */
+static int xilinx_cpm_pcie_parse_port(struct xilinx_cpm_pcie *port)
+{
+ struct device *dev = port->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") {
+ port->perst_gpio = devm_fwnode_gpiod_get(dev,
+ of_fwnode_handle(pcie_port_node),
+ "reset", GPIOD_OUT_HIGH,
+ NULL);
+ if (IS_ERR(port->perst_gpio)) {
+ if (PTR_ERR(port->perst_gpio) == -ENOENT) {
+ port->perst_gpio = NULL;
+ return 0;
+ }
+ return dev_err_probe(dev, PTR_ERR(port->perst_gpio),
+ "Failed to request reset GPIO\n");
+ }
+ return 0;
+ }
+
+ return 0;
+}
+
/**
* xilinx_cpm_pcie_parse_dt - Parse Device tree
* @port: PCIe port information
@@ -525,6 +588,19 @@ static int xilinx_cpm_pcie_parse_dt(struct xilinx_cpm_pcie *port,
struct device *dev = port->dev;
struct platform_device *pdev = to_platform_device(dev);
struct resource *res;
+ int ret;
+
+ /* CPM5NC does not support PERST# handling yet */
+ if (port->variant->version != CPM5NC_HOST) {
+ port->rstc = devm_reset_control_get_optional_exclusive(dev, NULL);
+ if (IS_ERR(port->rstc))
+ return dev_err_probe(dev, PTR_ERR(port->rstc),
+ "Failed to request reset\n");
+
+ ret = xilinx_cpm_pcie_parse_port(port);
+ if (ret)
+ return ret;
+ }
port->cpm_base = devm_platform_ioremap_resource_byname(pdev,
"cpm_slcr");
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 4469e1a77f3c..bf53354dc5a9 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -39,6 +39,15 @@ struct pcie_tlp_log;
*/
#define PCIE_T_PERST_CLK_US 100
+/*
+ * PERST# active time.
+ *
+ * See the "Power Sequencing and Reset Signal Timings" table of the PCI Express
+ * Card Electromechanical Specification, Revision 6.0, Section 2.11.2, Symbol
+ * "T_PERST".
+ */
+#define PCIE_T_PERST_US 100
+
/*
* PCIe r6.0, sec 5.3.3.2.1 <PME Synchronization>
* Recommends 1ms to 10ms timeout to check L2 ready.
--
2.44.4
next prev parent reply other threads:[~2026-08-07 12:35 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-07 12:35 [PATCH v8 0/2] Add support for PCIe RP PERST# Sai Krishna Musham
2026-08-07 12:35 ` [PATCH v8 1/2] dt-bindings: PCI: xilinx-versal-cpm: Add PERST# and reset support Sai Krishna Musham
2026-08-07 12:42 ` sashiko-bot
2026-08-07 12:35 ` Sai Krishna Musham [this message]
2026-08-07 12:53 ` [PATCH v8 2/2] PCI: xilinx-cpm: Add support for PCIe RP PERST# signal sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260807123507.3418671-3-sai.krishna.musham@amd.com \
--to=sai.krishna.musham@amd.com \
--cc=bharat.kumar.gogada@amd.com \
--cc=bhelgaas@google.com \
--cc=cassel@kernel.org \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=krzk+dt@kernel.org \
--cc=kw@linux.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=lpieralisi@kernel.org \
--cc=mani@kernel.org \
--cc=michal.simek@amd.com \
--cc=robh@kernel.org \
--cc=thippeswamy.havalige@amd.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox