说明

本文记录一次 ROCK 4D 搭配 Radxa Dual 2.5G Router HAT V1.5 时的 PCIe 排查过程。HAT 上的两块 RTL8125 可以正常工作,但通过 16Pin FPC 接入 ASM1182E PCIe Switch 扩展板后,扩展板及其后的 Intel Optane NVMe 在冷启动时无法枚举。

最后确认,问题不在 PCIe 数据线、ASM1182E 或 NVMe 本身,而是 FPC 的 POWER_EN 没有在 PCIe 第一次扫描前拉高。用户态临时上电可以让 ASM1182E 出现,但此时 PCI bus number 已经分配完毕,Switch 后面的 NVMe 仍然无法展开。最终通过设备树 GPIO hog 在启动早期拉高使能脚,完成了整条链路的冷启动枚举。

本文对应的设备树修改保存在我的 GitHub 仓库 ovo-ukiyo/openwrtrock-4d-aic8800-router-hat 分支中。完整补丁和提交记录会在后文给出。

硬件与原始拓扑

测试环境如下:

  • ROCK 4D,SoC 为 RK3576;
  • Radxa Dual 2.5G Router HAT V1.5,主芯片为 ASM2806;
  • ASM1182E 双口 PCIe Gen2 Switch 扩展板;
  • Intel Optane NVMe;
  • OpenWrt 25.12 开发版本,Linux 6.12。

原始冷启动的 PCIe 拓扑为:

1
2
3
4
-[0000:00]---00.0-[01-ff]----00.0-[02-06]--+-00.0-[03]----00.0
+-02.0-[04]--
+-06.0-[05]----00.0
\-0e.0-[06]----00.0

对应的硬件关系为:

1
2
3
4
5
6
RK3576
└─ ASM2806
├─ 02:00 → 本地 PCIe 设备
├─ 02:02 → 16Pin FPC,启动时为空
├─ 02:06 → RTL8125
└─ 02:0e → RTL8125

ASM2806 的固定下游设备能够正常识别,只有 02:02.0 后面的 FPC 分支为空。

先排除扩展板和 NVMe

将 ASM1182E 扩展板绕过 Router HAT,直接连接到 ROCK 4D 后,得到完整拓扑:

1
2
3
4
5
00:00.0 RK3576 Root Port
01:00.0 ASM1182E upstream
02:03.0 ASM1182E downstream
02:07.0 ASM1182E downstream
03:00.0 Intel Optane NVMe

这套连接可以稳定运行在 PCIe Gen2 x1。由此可以排除 ASM1182E、Optane 以及扩展板本身的基本硬件故障,排查重点转向 Router HAT 的 FPC 接口及启动时序。

定位 FPC 的电源使能脚

Router HAT 使用 ROCK 4D 40Pin 的物理 Pin16 控制 FPC 侧带信号。引脚对应关系为:

1
2
3
4
ROCK 4D 40Pin Pin16
→ GPIO2_B6
→ gpiochip2 offset 14
→ Router HAT FPC Pin13

OpenWrt 启动后查询该 GPIO:

1
gpioinfo -c gpiochip2 14

输出为:

1
gpiochip2 14 unnamed input

继续分别读取默认、上拉和下拉状态:

1
2
3
gpioget -c gpiochip2 14
gpioget -b pull-up -c gpiochip2 14
gpioget -b pull-down -c gpiochip2 14

三种情况下都得到:

1
"14"=inactive

万用表测量结果为:

1
2
40Pin Pin16:0 V
FPC Pin13: 0 V

断电后 Pin16 对地电阻约为 51.2 kΩ,没有硬短路。

用用户态 GPIO 验证因果关系

为了确认这个引脚的实际功能,启动后临时将它输出为高电平:

1
gpioset -c gpiochip2 14=1

操作后的变化很直接:

1
2
3
40Pin Pin16:0 V → 3.3 V
FPC Pin13: 0 V → 3.3 V
ASM1182E PWR LED:熄灭 → 点亮

随后执行 PCIe rescan,系统立即识别到:

1
04:00.0 PCI bridge: ASMedia Technology Inc. ASM1182e 2-Port PCIe x1 Gen2 Packet Switch

电平、指示灯和 PCIe 枚举同步变化,能够确定 GPIO2_B6 控制的 FPC Pin13 就是该扩展板的 POWER_EN。原始 OpenWrt 设备树没有配置这个信号,导致扩展板冷启动时没有真正 Enable。

FPC 上测得 5 V、PERST# 约为 3.3 V,并不能说明扩展板已经完成上电。对这块扩展板来说,POWER_EN 仍是必需条件。

热使能后 NVMe 仍然不出现

将 GPIO 拉高后,ASM1182E 本身已经出现在 lspci 中,但它后面的 NVMe 仍无法使用。内核日志给出了明确原因:

1
2
pci 0000:04:00.0: devices behind bridge are unusable because [bus 05] cannot be assigned for them
pcieport 0000:02:02.0: bridge has subordinate 04 but max busn 05

热使能后的拓扑为:

1
2
3
4
-[0000:00]---00.0-[01-ff]----00.0-[02-06]--+-00.0-[03]----00.0
+-02.0-[04]----00.0-[05]--
+-06.0-[05]----00.0
\-0e.0-[06]----00.0

两个分支都试图使用 bus 05。

系统第一次扫描时,02:02.0 后面没有设备,所以内核只为这个空分支分配了一个 bus:

1
2
3
primary=02
secondary=04
subordinate=04

用户态给扩展板上电后,ASM1182E 可以出现在 bus 04,但 ASM1182E 自身还是一颗 PCIe Switch。它需要新的 bus number 才能继续枚举下游桥和 NVMe。此时 bus 05 已经分配给另一条 ASM2806 分支,上级桥的 subordinate 也被限制为 04,因此无法容纳完整拓扑。

普通 NVMe 是 Endpoint,挂在 bus 04 后通常不再要求额外的下游 bus。ASM1182E 则不同:

1
2
3
普通 NVMe:ASM2806 → bus 04 → NVMe

二级 Switch:ASM2806 → bus 04 → ASM1182E → 新 bus → NVMe

所以 gpioset 和 PCI rescan 只能用于确认硬件链路,不能作为最终启动方案。

在设备树中提前使能

修复的关键是让 GPIO2_B6 在 RK3576 PCIe Host 第一次扫描之前就输出高电平。本次在 ROCK 4D 设备树的 gpio2 节点中加入 GPIO hog:

1
2
3
4
5
6
7
8
&gpio2 {
router_hat_pcie_enable_hog: router-hat-pcie-enable-hog {
gpio-hog;
gpios = <RK_PB6 GPIO_ACTIVE_HIGH>;
output-high;
line-name = "router-hat-pcie-enable";
};
};

对应的 OpenWrt 补丁为:

1
target/linux/rockchip/patches-6.12/051-12-rock4d-router-hat-pcie-enable.patch

完整修改可以直接查看:

这份补丁本身很短,关键在生效时间。GPIO hog 会在 gpio2 控制器注册时立即申请 GPIO2_B6 并输出高电平,不需要等待 init 脚本、hotplug 脚本或网络服务启动。ASM1182E 因此能在 PCIe Host 第一次遍历总线之前完成供电,内核看到的是一棵完整的桥拓扑,而不是启动时为空、运行后才出现的端口。

GPIO hog 会在 GPIO 控制器注册时申请并拉高该引脚,时间早于 PCIe 主机完成初次枚举。这样 ASM1182E 在扫描开始前已经工作,Linux 可以根据完整拓扑统一分配 bus number。

冷启动验证

验证时需要彻底断电再上电,不能预先执行 gpioset、PCI rescan 或链路重训。启动后检查:

1
2
3
4
5
gpioinfo -c gpiochip2 14
gpioget -c gpiochip2 14
lspci
lspci -t
dmesg | grep -Ei '1182|nvme|busn|bridge|pcie'

最终结果为:

  • GPIO line 显示名称 router-hat-pcie-enable,方向和电平为 output-high;
  • ASM1182E upstream bridge 出现在 04:00.0
  • ASM1182E 下游桥出现在 05:03.005:07.0
  • Intel Optane NVMe 出现在 06:00.0
  • 两块 RTL8125 的 bus number 自动向后顺延,不再与 ASM1182E 分支冲突;
  • 原来的 bus number 报错消失;
  • NVMe 可以正常挂载到 /opt

小结

这次故障由启动时序和 PCIe 拓扑共同造成。GPIO2_B6 没有拉高,使 FPC 下游 ASM1182E 在第一次扫描时处于关闭状态;用户态上电虽然能找回 Switch,但 PCI bus number 已经按照空分支分配,无法继续容纳 Switch 后面的设备。

最终修复不是增加延时扫描,也不是启动脚本中反复 rescan,而是在设备树中尽早拉高 POWER_EN。完整拓扑在第一次扫描时可见后,Linux 会自动完成正确的 bus 分配。

这项设置与 Router HAT 的硬件连接有关。若后续提交上游,更适合评估为 HAT overlay 或其他板卡专用描述,避免在所有 ROCK 4D 的基础设备树中无条件占用该 GPIO。