ArXen42 Posted Saturday at 02:43 PM Posted Saturday at 02:43 PM (edited) In our testing, when attempting to use various Wi-Fi mini-PCIe/M.2 adapters from Intel and Realtek, we've encountered problem: oftentimes OS will not see PCIe device with error "PCIe link training gen1 timeout". Some days it happens only in 1/10 boots, other days it can stop working completely. After long debugging we've found that 24-pin FPC cable that connects Orangepi and official connector board (PCIE-SOCKET-OPI4-4B) does not pass PERST signal from Orangepi. Instead, it is high by default and the only way to temporarily set it to low is by pressing physical button on connector board. As far as I understand, PERST signal basically tells the connected device that power and clocks are stable and it can begin link training sequence. Normally, this signal would be controlled from driver code (pcie_rockchip_host.c, rockchip->perst_gpio field) and is assigned to GPIO2_4 pin. During startup sequence it must first be set to low for some time before being set to high after all PCIe clocks are initialized. However, since we don't connect PCI-e directly to rk3399 but through connector cable/board, this code does nothing and instead PERST signal is always high as soon as power is on, leading to link training errors. Simple method to verify the problem: Build custom image (or only kernel) using armbian-build. In kernel configuration, set pcie_rockchip_host module to be compiled as loadable module (<M>) instead of built-in by default. When system fails to see connected PCI-E device at boot, press the reset button on connector board. Execute (you can try this first without pressing button but it will not work): sudo modprobe -vr pcie_rockchip_host && sudo modprobe -v pcie_rockchip_host `lspci` command should now show your device. Thankfully, 24-pin FPC cable does pass GPIO1_A0 signal which we can use as a workaround. By default it is configured as vcc3v3-pcie power regulator, which basically means that it is always on. If we reconfigure it to act as PERST signal, it will become controlled by pcie_rockchip_host Linux driver, which seems to fix the problem. So, the fix is to build custom image/kernel with dts patch below applied (it removes vcc3v3-pcie-regulator nodes and modifies ep-gpios in &pcie0 to use GPIO1_A0): From 8abd7c990fc6f052f335b71df009ec8b88f57a88 Mon Sep 17 00:00:00 2001 From: ArXen42 <arxen42@tutanota.com> Date: Sun, 13 Apr 2025 19:05:52 +0300 Subject: [PATCH] Changed GPIO1_A0 on Orangepi 4 LTS from static power regulator to PCI-E PERST pin --- .../dt/rk3399-orangepi-4-lts.dts | 20 +------------------ 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/patch/kernel/archive/rockchip64-6.14/dt/rk3399-orangepi-4-lts.dts b/patch/kernel/archive/rockchip64-6.14/dt/rk3399-orangepi-4-lts.dts index c79940457..41eece5a4 100644 --- a/patch/kernel/archive/rockchip64-6.14/dt/rk3399-orangepi-4-lts.dts +++ b/patch/kernel/archive/rockchip64-6.14/dt/rk3399-orangepi-4-lts.dts @@ -128,17 +128,6 @@ }; }; - vcc3v3_pcie: vcc3v3-pcie-regulator { - compatible = "regulator-fixed"; - enable-active-high; - gpio = <&gpio1 RK_PA0 GPIO_ACTIVE_HIGH>; - pinctrl-names = "default"; - pinctrl-0 = <&pcie_drv>; - regulator-always-on; - regulator-boot-on; - regulator-name = "vcc3v3_pcie"; - }; - vcc3v3_sys: vcc3v3-sys { compatible = "regulator-fixed"; regulator-name = "vcc3v3_sys"; @@ -899,7 +888,7 @@ &pcie0 { status = "okay"; - ep-gpios = <&gpio2 4 GPIO_ACTIVE_HIGH>; + ep-gpios = <&gpio1 0 GPIO_ACTIVE_HIGH>; num-lanes = <4>; max-link-speed = <1>; }; @@ -1095,13 +1084,6 @@ drive-strength = <12>; }; - pcie { - pcie_drv: pcie-drv { - rockchip,pins = - <1 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>; - }; - }; - hdmi { /delete-node/ hdmi-i2c-xfer; }; -- 2.49.0 While this doesn't address schematic problem (we still don't control PERST signal directly), this seems to work nontheless. I think it works because now the following happens: 1) Driver powers off PCIe device (thinking it set PERST signal to low) 2) Driver sets clocks and other PCIe machinery necessary 3) Driver powers on the board, but this time the clock signals are already up and running, so Wi-Fi/SSD/whatever chip initializes propely. At least, that's how I interpret what's happening in driver code below. static int rockchip_pcie_host_init_port(struct rockchip_pcie *rockchip) { struct device *dev = rockchip->dev; int err, i = MAX_LANE_NUM; u32 status; gpiod_set_value_cansleep(rockchip->perst_gpio, 0); // <--- this powers off PCIe device err = rockchip_pcie_init_port(rockchip); if (err) return err; /* Fix the transmitted FTS count desired to exit from L0s. */ status = rockchip_pcie_read(rockchip, PCIE_CORE_CTRL_PLC1); status = (status & ~PCIE_CORE_CTRL_PLC1_FTS_MASK) | (PCIE_CORE_CTRL_PLC1_FTS_CNT << PCIE_CORE_CTRL_PLC1_FTS_SHIFT); rockchip_pcie_write(rockchip, status, PCIE_CORE_CTRL_PLC1); rockchip_pcie_set_power_limit(rockchip); /* Set RC's clock architecture as common clock */ status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_LCS); status |= PCI_EXP_LNKSTA_SLC << 16; rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_LCS); /* Set RC's RCB to 128 */ status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_LCS); status |= PCI_EXP_LNKCTL_RCB; rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_LCS); /* Enable Gen1 training */ rockchip_pcie_write(rockchip, PCIE_CLIENT_LINK_TRAIN_ENABLE, PCIE_CLIENT_CONFIG); msleep(PCIE_T_PVPERL_MS); gpiod_set_value_cansleep(rockchip->perst_gpio, 1); // <--- this powers PCIe device back on after all clocks are set up msleep(PCIE_T_RRS_READY_MS); /* 500ms timeout value should be enough for Gen1/2 training */ err = readl_poll_timeout(rockchip->apb_base + PCIE_CLIENT_BASIC_STATUS1, status, PCIE_LINK_UP(status), 20, 500 * USEC_PER_MSEC); if (err) { dev_err(dev, "PCIe link training gen1 timeout!\n"); goto err_power_off_phy; } If you continue to encounter problems with this approach, one other option left is to modify the board itself by rerouting GPIO1_A0 signal to PERST, and leaving 3v power always on, but this will require some soldering work. Changed-GPIO1_A0-on-Orangepi-4-LTS-from-static-power-to-PERST.patch Edited Saturday at 07:50 PM by ArXen42 1 Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.