* [PATCH v5 1/2] dt-bindings: PCI: rockchip,rk3399-pcie: Add PERST# inactive delay properties
2026-11-04 21:58 [PATCH v5 0/2] PCI: rockchip-host: Make the PERST# inactive delay configurable Enrique Hernández Bello
@ 2026-11-04 21:58 ` Enrique Hernández Bello
2026-11-05 12:23 ` Krzysztof Kozlowski
2026-11-04 21:58 ` [PATCH v5 2/2] PCI: rockchip-host: Make the PERST# inactive delay configurable Enrique Hernández Bello
2026-11-05 1:44 ` [PATCH v5 0/2] " Igor Velkov
2 siblings, 1 reply; 6+ messages in thread
From: Enrique Hernández Bello @ 2026-11-04 21:58 UTC (permalink / raw)
To: shawn.lin, lpieralisi, kwilczynski, mani, bhelgaas
Cc: robh, krzk+dt, conor+dt, heiko, dlemoal, iav, devicetree,
linux-pci, linux-rockchip, linux-arm-kernel, linux-kernel,
Enrique Hernández Bello
The driver holds PERST# asserted for T_PVPERL (100 ms) before releasing it.
Endpoints disagree about what they want there: some need longer than the
default to settle, while others stop answering configuration reads when the
reset pulse is stretched that far, because PERST# stays asserted for the
whole wait.
Describe two properties so a board can state what its endpoint needs, named
after the ones the Rockchip vendor driver already uses for the dwc-based
controllers:
rockchip,perst-inactive-ms - the delay used at probe
rockchip,s2r-perst-inactive-ms - the delay used when resuming
Both are optional and the defaults preserve the current behaviour.
Signed-off-by: Enrique Hernández Bello <ehbello@gmail.com>
---
.../bindings/pci/rockchip,rk3399-pcie.yaml | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/Documentation/devicetree/bindings/pci/rockchip,rk3399-pcie.yaml b/Documentation/devicetree/bindings/pci/rockchip,rk3399-pcie.yaml
index 720a5f9..7ac915c 100644
--- a/Documentation/devicetree/bindings/pci/rockchip,rk3399-pcie.yaml
+++ b/Documentation/devicetree/bindings/pci/rockchip,rk3399-pcie.yaml
@@ -40,6 +40,21 @@ properties:
maxItems: 1
description: pre-reset GPIO
+ rockchip,perst-inactive-ms:
+ default: 100
+ description:
+ Time PERST# is held asserted before it is released, which is also the
+ width of the reset pulse. The default meets T_PVPERL for a slot that
+ is powered at the moment PERST# is asserted. Some endpoints need more
+ settling time than that, while others stop responding when the pulse
+ is that long. A value of 0 selects the 100 us minimum the PCI Express
+ CEM specification sets for the pulse.
+
+ rockchip,s2r-perst-inactive-ms:
+ description:
+ The same time, applied when resuming from system suspend. Defaults to
+ the value of rockchip,perst-inactive-ms.
+
vpcie12v-supply:
description: The 12v regulator to use for PCIe.
--
2.56.0
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [PATCH v5 1/2] dt-bindings: PCI: rockchip,rk3399-pcie: Add PERST# inactive delay properties
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-05 12:23 ` Krzysztof Kozlowski
2026-11-05 17:40 ` Enrique Hernández Bello
0 siblings, 1 reply; 6+ messages in thread
From: Krzysztof Kozlowski @ 2026-11-05 12:23 UTC (permalink / raw)
To: Enrique Hernández Bello
Cc: shawn.lin, lpieralisi, kwilczynski, mani, bhelgaas, robh,
krzk+dt, conor+dt, heiko, dlemoal, iav, devicetree, linux-pci,
linux-rockchip, linux-arm-kernel, linux-kernel
On Wed, Nov 04, 2026 at 09:58:46PM +0000, Enrique Hernández Bello wrote:
> The driver holds PERST# asserted for T_PVPERL (100 ms) before releasing it.
> Endpoints disagree about what they want there: some need longer than the
> default to settle, while others stop answering configuration reads when the
> reset pulse is stretched that far, because PERST# stays asserted for the
> whole wait.
>
> Describe two properties so a board can state what its endpoint needs, named
> after the ones the Rockchip vendor driver already uses for the dwc-based
> controllers:
Vendor driver does not matter, it is antipattern. Do not mention it here
as reason to do such change.
>
> rockchip,perst-inactive-ms - the delay used at probe
> rockchip,s2r-perst-inactive-ms - the delay used when resuming
No need to repeat the diff.
>
> Both are optional and the defaults preserve the current behaviour.
>
> Signed-off-by: Enrique Hernández Bello <ehbello@gmail.com>
> ---
> .../bindings/pci/rockchip,rk3399-pcie.yaml | 15 +++++++++++++++
> 1 file changed, 15 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/pci/rockchip,rk3399-pcie.yaml b/Documentation/devicetree/bindings/pci/rockchip,rk3399-pcie.yaml
> index 720a5f9..7ac915c 100644
> --- a/Documentation/devicetree/bindings/pci/rockchip,rk3399-pcie.yaml
> +++ b/Documentation/devicetree/bindings/pci/rockchip,rk3399-pcie.yaml
> @@ -40,6 +40,21 @@ properties:
> maxItems: 1
> description: pre-reset GPIO
>
> + rockchip,perst-inactive-ms:
> + default: 100
> + description:
> + Time PERST# is held asserted before it is released, which is also the
> + width of the reset pulse. The default meets T_PVPERL for a slot that
> + is powered at the moment PERST# is asserted. Some endpoints need more
> + settling time than that, while others stop responding when the pulse
> + is that long. A value of 0 selects the 100 us minimum the PCI Express
us or ms?
> + CEM specification sets for the pulse.
What is the nature of this timing? 100 ms is a lot. Are you sure you are
not describing RC delay (we have bindings for that already)
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v5 1/2] dt-bindings: PCI: rockchip,rk3399-pcie: Add PERST# inactive delay properties
2026-11-05 12:23 ` Krzysztof Kozlowski
@ 2026-11-05 17:40 ` Enrique Hernández Bello
0 siblings, 0 replies; 6+ messages in thread
From: Enrique Hernández Bello @ 2026-11-05 17:40 UTC (permalink / raw)
To: krzk
Cc: shawn.lin, lpieralisi, kwilczynski, mani, bhelgaas, robh,
krzk+dt, conor+dt, heiko, dlemoal, iav, devicetree, linux-pci,
linux-rockchip, linux-arm-kernel, linux-kernel
On Thu, Nov 05, 2026, Krzysztof Kozlowski wrote:
> Vendor driver does not matter, it is antipattern. Do not mention it here
> as reason to do such change.
>
> No need to repeat the diff.
Understood, both go in the next version.
> us or ms?
ms. The 0 case is badly worded: the driver never holds PERST# for less
than 100 us, whatever the value, and 0 just ends up at that floor. I will
describe the floor instead of giving 0 a meaning of its own.
> What is the nature of this timing? 100 ms is a lot. Are you sure you are
> not describing RC delay (we have bindings for that already)
The 100 ms is not something the board needs. It is the driver's current
wait, T_PVPERL from the CEM spec, applied on every board. Because PERST#
is already asserted when that wait starts, it is also the width of the
reset pulse.
On my board (ROCK Pi 4C) the slot supply is regulator-always-on, so power
has been stable for seconds before probe and there is nothing left to
settle. The problem goes the other way: the JMB585 behind it stops
answering configuration reads when it is held in reset that long. A wait
of 0 to 15 ms enumerated 17 times out of 17, 20 ms once out of 3, and
100 ms never in 5. So the board needs a shorter value, not a longer one.
I do not know why this endpoint behaves this way.
Which binding did you have in mind for the RC delay? If an existing one
fits, I would rather use it.
I also plan to drop rockchip,s2r-perst-inactive-ms, since it describes
an OS power state rather than the hardware.
Thanks,
Enrique
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v5 2/2] PCI: rockchip-host: Make the PERST# inactive delay configurable
2026-11-04 21:58 [PATCH v5 0/2] PCI: rockchip-host: Make the PERST# inactive delay configurable 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
2026-11-05 1:44 ` [PATCH v5 0/2] " Igor Velkov
2 siblings, 0 replies; 6+ messages in thread
From: Enrique Hernández Bello @ 2026-11-04 21:58 UTC (permalink / raw)
To: shawn.lin, lpieralisi, kwilczynski, mani, bhelgaas
Cc: robh, krzk+dt, conor+dt, heiko, dlemoal, iav, devicetree,
linux-pci, linux-rockchip, linux-arm-kernel, linux-kernel,
Enrique Hernández Bello
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
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [PATCH v5 0/2] PCI: rockchip-host: Make the PERST# inactive delay configurable
2026-11-04 21:58 [PATCH v5 0/2] PCI: rockchip-host: Make the PERST# inactive delay configurable 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 ` [PATCH v5 2/2] PCI: rockchip-host: Make the PERST# inactive delay configurable Enrique Hernández Bello
@ 2026-11-05 1:44 ` Igor Velkov
2 siblings, 0 replies; 6+ messages in thread
From: Igor Velkov @ 2026-11-05 1:44 UTC (permalink / raw)
To: Enrique Hernández Bello
Cc: iav, shawn.lin, lpieralisi, kwilczynski, mani, bhelgaas, robh,
krzk+dt, conor+dt, heiko, dlemoal, devicetree, linux-pci,
linux-rockchip, linux-arm-kernel, linux-kernel
Tested on Helios64 (JMB585 behind a GPIO-switched slot supply) and
ROCK Pi 4A (empty slot and a WD SN770 NVMe), 7.3.1 with the series
backported, one s2idle cycle per boot:
Helios64, no property: resume 20/20, abort in rockchip_pcie_rd_conf() at probe on 1 of 21 boots
Helios64, <10> probe and s2r: resume 20/20, the same abort on 1 of 21 boots
ROCK Pi 4A, empty slot, none/<10>: 10/10, 10/10
ROCK Pi 4A, SN770, none/<10>: 10/10, 10/10, NVMe readable after each resume
The default behaves as before, and 10 ms changes nothing here; the
slow JMB585 link on Helios64 shows up at the same rate with either
pulse width.
Tested-by: Igor Velkov <iav@iav.lv>
^ permalink raw reply [flat|nested] 6+ messages in thread