From: "Enrique Hernández Bello" <ehbello@gmail.com>
To: shawn.lin@rock-chips.com, lpieralisi@kernel.org,
kwilczynski@kernel.org, mani@kernel.org, bhelgaas@google.com
Cc: robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org,
heiko@sntech.de, dlemoal@kernel.org, iav@iav.lv,
devicetree@vger.kernel.org, linux-pci@vger.kernel.org,
linux-rockchip@lists.infradead.org,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org,
"Enrique Hernández Bello" <ehbello@gmail.com>
Subject: [PATCH v5 2/2] PCI: rockchip-host: Make the PERST# inactive delay configurable
Date: Wed, 4 Nov 2026 21:58:47 +0000 [thread overview]
Message-ID: <20261104215848.2087944-3-ehbello@gmail.com> (raw)
In-Reply-To: <20261104215848.2087944-1-ehbello@gmail.com>
rockchip_pcie_host_init_port() waits T_PVPERL, 100 ms, before releasing
PERST#. The GPIO is acquired with GPIOD_OUT_LOW early in probe, so PERST#
is already asserted when that wait starts, and the wait therefore sets the
reset pulse width as well.
That suits a board which powers the slot at the moment it asserts PERST#,
but endpoints do not agree on what they want. On a ROCK Pi 4C carrying a
JMB585 SATA controller, a pulse that long stops the endpoint answering
configuration reads at all. Measured on that board with a single kernel and
two module parameters, one sleeping before the GPIO is acquired and one in
place of the wait, timing the pulse with a ktime delta across the two
gpiod_set_value() calls:
pre (ms) post (ms) pulse trials enumerated
0 0 1-11 ms 5 5
0 10 ~18 ms 3 3
0 15 24-47 ms 4 4
0 20 ~28 ms 3 1
0 100 ~108 ms 4 0
200 0 6-11 ms 5 5
200 100 ~108 ms 1 0
Delaying the assertion changes nothing, while widening the pulse decides
everything. The slot supply on this board is regulator-always-on, so power
had been valid for seconds in every row above, the failing ones included.
Rather than change the delay for every board, read it from the device tree,
reusing the property names the Rockchip vendor driver already carries for
the dwc-based controllers in pcie-dw-rockchip.c. The default is unchanged,
so a board that describes nothing behaves exactly as before. Whatever the
board asks for, PERST# stays asserted for at least the 100 us minimum the
specification sets, which covers T_PERST and T_PERST-CLK.
Suggested-by: Shawn Lin <shawn.lin@rock-chips.com>
Link: https://lore.kernel.org/all/95aeecc0-2794-4cc6-a635-5c042afc1405@rock-chips.com/
Signed-off-by: Enrique Hernández Bello <ehbello@gmail.com>
---
drivers/pci/controller/pcie-rockchip-host.c | 26 +++++++++++++++++----
drivers/pci/controller/pcie-rockchip.h | 2 ++
2 files changed, 24 insertions(+), 4 deletions(-)
diff --git a/drivers/pci/controller/pcie-rockchip-host.c b/drivers/pci/controller/pcie-rockchip-host.c
index 5b071bd..5f78cd6 100644
--- a/drivers/pci/controller/pcie-rockchip-host.c
+++ b/drivers/pci/controller/pcie-rockchip-host.c
@@ -24,6 +24,7 @@
#include <linux/of_pci.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/regulator/consumer.h>
#include "../pci.h"
@@ -280,8 +281,10 @@ static void rockchip_pcie_set_power_limit(struct rockchip_pcie *rockchip)
/**
* rockchip_pcie_host_init_port - Initialize hardware
* @rockchip: PCIe port information
+ * @perst_inactive_ms: how long to hold PERST# asserted before releasing it
*/
-static int rockchip_pcie_host_init_port(struct rockchip_pcie *rockchip)
+static int rockchip_pcie_host_init_port(struct rockchip_pcie *rockchip,
+ u32 perst_inactive_ms)
{
struct device *dev = rockchip->dev;
int err, i = MAX_LANE_NUM;
@@ -315,7 +318,12 @@ static int rockchip_pcie_host_init_port(struct rockchip_pcie *rockchip)
rockchip_pcie_write(rockchip, PCIE_CLIENT_LINK_TRAIN_ENABLE,
PCIE_CLIENT_CONFIG);
- msleep(PCIE_T_PVPERL_MS);
+ /*
+ * PERST# has been asserted since the GPIO was acquired, so this wait
+ * is also the reset pulse width. Never go below the specification
+ * minimum, which covers both T_PERST and T_PERST-CLK, each 100 us.
+ */
+ fsleep(max(perst_inactive_ms * USEC_PER_MSEC, PCIE_T_PERST_CLK_US));
gpiod_set_value_cansleep(rockchip->perst_gpio, 1);
msleep(PCIE_RESET_CONFIG_WAIT_MS);
@@ -587,6 +595,14 @@ static int rockchip_pcie_parse_host_dt(struct rockchip_pcie *rockchip)
if (IS_ERR(rockchip->vpcie0v9))
return PTR_ERR(rockchip->vpcie0v9);
+ if (device_property_read_u32(dev, "rockchip,perst-inactive-ms",
+ &rockchip->perst_inactive_ms))
+ rockchip->perst_inactive_ms = PCIE_T_PVPERL_MS;
+
+ if (device_property_read_u32(dev, "rockchip,s2r-perst-inactive-ms",
+ &rockchip->s2r_perst_inactive_ms))
+ rockchip->s2r_perst_inactive_ms = rockchip->perst_inactive_ms;
+
return 0;
}
@@ -881,7 +897,8 @@ static int rockchip_pcie_resume_noirq(struct device *dev)
if (err)
goto err_disable_0v9;
- err = rockchip_pcie_host_init_port(rockchip);
+ err = rockchip_pcie_host_init_port(rockchip,
+ rockchip->s2r_perst_inactive_ms);
if (err)
goto err_pcie_resume;
@@ -938,7 +955,8 @@ static int rockchip_pcie_probe(struct platform_device *pdev)
goto err_set_vpcie;
}
- err = rockchip_pcie_host_init_port(rockchip);
+ err = rockchip_pcie_host_init_port(rockchip,
+ rockchip->perst_inactive_ms);
if (err)
goto err_vpcie;
diff --git a/drivers/pci/controller/pcie-rockchip.h b/drivers/pci/controller/pcie-rockchip.h
index b5da156..c773f74 100644
--- a/drivers/pci/controller/pcie-rockchip.h
+++ b/drivers/pci/controller/pcie-rockchip.h
@@ -315,6 +315,8 @@ struct rockchip_pcie {
struct regulator *vpcie1v8; /* 1.8V power supply */
struct regulator *vpcie0v9; /* 0.9V power supply */
struct gpio_desc *perst_gpio;
+ u32 perst_inactive_ms;
+ u32 s2r_perst_inactive_ms;
u32 lanes;
u8 lanes_map;
int link_gen;
--
2.56.0
next prev parent reply other threads:[~2026-11-04 21:58 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-04 21:58 [PATCH v5 0/2] " Enrique Hernández Bello
2026-11-04 21:58 ` [PATCH v5 1/2] dt-bindings: PCI: rockchip,rk3399-pcie: Add PERST# inactive delay properties Enrique Hernández Bello
2026-11-04 21:58 ` Enrique Hernández Bello [this message]
2026-11-05 1:44 ` [PATCH v5 0/2] PCI: rockchip-host: Make the PERST# inactive delay configurable Igor Velkov
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=20261104215848.2087944-3-ehbello@gmail.com \
--to=ehbello@gmail.com \
--cc=bhelgaas@google.com \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=dlemoal@kernel.org \
--cc=heiko@sntech.de \
--cc=iav@iav.lv \
--cc=krzk+dt@kernel.org \
--cc=kwilczynski@kernel.org \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=linux-rockchip@lists.infradead.org \
--cc=lpieralisi@kernel.org \
--cc=mani@kernel.org \
--cc=robh@kernel.org \
--cc=shawn.lin@rock-chips.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
all inboxes | Powered by JetHome®