RK3568 PCIe3.0 x2链路训练与设备树配置实战解析
发布时间:2026/9/28 3:43:26来源:尧图网络
RK3568这颗SoC在嵌入式圈子里这两年出镜率实在太高了做边缘计算盒子、工业HMI、机器视觉、桌面终端甚至一些轻量级NAS方案都能看到它的影子。它最让人心动的地方是接口非常全双千兆网口、SATA、USB3.0、PCIe2.0、PCIe3.0全都集成在一起尤其那个PCIe3.0x2接口基本就是给NVMe SSD或者高速网卡准备的。但我得说句实在话这颗SoC的PCIe3.0x2并不是“接上就能跑”硬件上稍有疏忽或者设备树配置不对链路训练就会一直卡在Detect状态lspci里连个鬼影都看不到。这篇文章就是把我最近一个真实项目的调试过程完整梳理一遍。项目本身是一块基于RK3568的工业控制板PCIe3.0x2接口用来接工业级NVMe固态硬盘同时还涉及扩展PCIe网卡的需求。整个过程从硬件电路设计阶段就开始介入一直到设备树配置、内核启动、驱动加载前前后后踩了不少坑也沉淀了一些可以复用的排查思路。如果你正好在做RK3568相关项目尤其是涉及PCIe3.0x2的这篇文章应该能帮你少走不少弯路。1. 项目背景与整体思路1.1 为什么PCIe3.0x2会成为项目关键点RK3568这颗芯片的PCIe资源其实有点“复杂”PCIe3.0有两个控制器pcie3x2PCIe3.0 x2和pcie3x1PCIe3.0 x1但是它们共用同一个PCIe3.0 PHY也就是说你启用了PCIe3.0 x2PCIe3.0 x1就不能用了反过来也一样。另外还有一个独立的pcie2x1控制器PCIe2.0 x1这个一般用来接WiFi模组之类对带宽要求不高的设备。所以如果你的设计需要用PCIe3.0接口接NVMe SSD那么大概率只能用x2通道x1通道只能放弃或者改作他用。这个“二选一”的约束在项目早期如果没搞清楚后面画PCB、写设备树都会很痛苦。PCIe3.0x2理论带宽大约16GT/s每个lane 8GT/s两条lane换算成有效数据带宽大概在2GB/s左右对于大多数NVMe SSD和千兆/万兆网卡来说完全够用。但问题在于PCIe3.0的速率已经进入高速信号范畴链路训练、时序、信号完整性、供电稳定性每一环都不能出错。这和PCIe2.0时代的“焊接好就能用”完全是两码事。1.2 调试工作的总体流程与工程划分我把整个调试过程拆成了四个阶段按顺序执行硬件电路检查阶段确认供电、时钟、复位、差分走线、AC耦合电容等物理层条件是否满足PCIe规范。Uboot初始化阶段确认Bootloader能正确枚举PCIe设备如果这个阶段都过不了内核阶段不用看。内核启动阶段确认设备树配置正确内核能识别PCIe控制器并完成设备枚举。驱动与应用阶段确认驱动加载正常设备能正常读写带宽和稳定性达标。这个顺序很重要我见过太多人一上来就改设备树、改内核结果折腾半天发现是硬件上PERST#复位信号根本没接对。调试一定要分层先把物理层确认了再谈软件配置。2. 硬件电路设计物理层决定成败2.1 RK3568 PCIe资源与引脚分配先理清楚RK3568的PCIe相关引脚和控制器资源。这颗SoC上跟PCIe相关的主要有这几个模块控制器节点接口规格复用PHY典型用途pcie3x2PCIe3.0 x2PCIe30 PHYNVMe SSD、双口网卡pcie3x1PCIe3.0 x1PCIe30 PHY与x2共用千兆网卡、WiFi6模组pcie2x1PCIe2.0 x1Combphy2与SATA0/USB3复用WiFi5模组、低速网卡实际项目中如果你用了PCIe3.0x2的NVMe SSD那么在设备树里就必须把pcie3x1节点status disabled否则PHY会被抢占导致两个控制器都起不来。这个我在后面设备树章节会再强调一遍。引脚上RK3568的PCIe3.0通道有标准的REFCLK/-差分对、TXP/TXN、RXP/RXN还有PERST#复位、CLKREQ#时钟请求、WAKE#唤醒可选。每个信号的具体GPIO复用关系要查RK3568的TRM和对应的设备树dtsi文件不要凭经验猜。2.2 供电电路设计要点PCIe接口的供电是第一个容易踩坑的地方。高速电路的供电要求比普通数字电路严格得多NVMe SSD供电典型要求是3.3V有些工业级SSD还会需要12V辅助供电。SSD在读写瞬间电流很大尤其是一些MLC/TLC企业级盘瞬时功耗可以到5W以上。供电电路至少要预留30%以上的电流余量并且要在SSD电源引脚附近放足够容量的去耦电容。我在实际调试中遇到过SSD在持续读写时偶发掉盘最后查出来是3.3V电源在负载跳变时跌落超过5%加上去耦电容和优化反馈环路后才解决。PCIe PHY供电RK3568内部PCIe PHY需要1.8V和0.9V供电这组电源纹波要控制在50mV以内否则会影响高速链路的信号质量。如果使用PMIC集成供电要检查对应的BUCK/LDO输出电容和纹波参数是否达标。供电时序PCIe规范要求PERST#信号必须在所有电源稳定之后至少延迟100ms再释放。这个时序如果反了SSD上电时序不符合协议有可能直接固件异常导致链路完全训练不起来。所以PERST#一般不要直接接一个RC就完事最好用GPIO控制配合一个延时电路或者由PMIC的电源好信号来触发。我画了个供电时序检查表供参考检查项规范要求实测方法3.3V SSD供电纹波 ≤ 5%电流余量 ≥ 30%示波器测纹波电子负载测电流1.8V/0.9V PHY供电纹波 ≤ 50mV示波器AC耦合测量PERST#释放时序晚于电源稳定 ≥ 100ms示波器双通道测时序REFCLK稳定上电后持续稳定输出示波器测频率/幅度2.3 时钟、复位与差分走线规范PCIe高速链路对物理层的要求可以总结成“一个时钟两个差分对一个复位”。REFCLK 100MHz差分时钟PCIe3.0对参考时钟的要求是频率准确度±300ppm以内抖动要小。RK3568的REFCLK可以由芯片内部输出也可以由外部晶体提供一般在设计时用SoC的REFCLK输出引脚直接接到PCIe插槽或设备端即可。但要注意的是参考时钟走线必须是差分对而且最好走内层远离其他高速信号阻抗控制在85Ω差分PCIe3.0规范要求85Ω不是USB/SATA的90Ω。参考时钟上不需要串AC耦合电容PCIe时钟是直流耦合的千万别和SerDes数据信号的AC耦合搞混。TX/RX差分数据线PCIe3.0每个lane包含一对TX和一对RX差分线阻抗要求85Ω±10%。数据线上必须串接AC耦合电容典型值100nF0.1uF位置要靠近发送端。走线时要做到对内等长、对间等长、参考地平面完整。差分对内等长控制在5mil以内对间等长控制在10mil以内尽量少打过孔非要打过孔的话要成对打减小阻抗不连续。PERST#复位信号这个信号是PCIe设备的异步复位低电平有效。前面说了要满足上电时序要求。另外PERST#不能被当作普通GPIO随便拉高拉低有些SSD对复位信号的毛刺很敏感需要在GPIO输出端加RC滤波或者缓冲器。CLKREQ#如果要支持ASPM电源管理尤其是NVMe SSD的L1.2低功耗状态CLKREQ#信号必须连接且正确配置。有些便宜的主板设计偷懒把CLKREQ#直接接地这样做虽然不影响基本功能但会丢失低功耗能力。工业设备如果不追求低功耗直接拉高或悬空也不是不能用但最好还是按规范接好。2.4 硬件设计Checklist与评审清单给各位整理一个我项目里实际用过的硬件设计检查清单[ ] PCIe3.0差分线阻抗设计为85Ω±10%实际生产后要做阻抗验证[ ] TX/RX数据线都串了0.1uF AC耦合电容且放在发送端一侧[ ] REFCLK差分对走线远离数据线不要交叉不要跨分割[ ] 差分对内等长≤5mil对间等长≤10mil[ ] PERST#由GPIO控制且满足上电延迟≥100ms的要求[ ] 3.3V供电电容余量足够建议在SSD座附近放4个100uF钽电容高频去耦电容[ ] PHY供电1.8V/0.9V纹波达标[ ] CLKREQ#正确连接或按设计意图处理[ ] 所有PCIe信号不要跨越模拟电源区域和时钟区域[ ] 预留测试点REFCLK测试点、PERST#测试点、差分线测试点方便调试最后一个测试点很重要我在项目中就因为预留了REFCLK和PERST#的测试点后面定位问题省了大量时间。如果硬件工程师说“没地方放测试点”你可以直接告诉他调试会多花三倍时间让他自己权衡。3. 设备树与内核配置让内核认识控制器3.1 RK3568 PCIe设备树节点解析硬件搞定之后就轮到设备树了。RK3568的设备树在Rockchip官方BSP源码里已经写得比较完善但默认很多节点是disabled状态需要根据实际设计打开。内核设备树中PCIe3.0 x2控制器节点一般长这样以Rockchip官方内核4.19/5.10分支为例pcie3x2: pciefe280000 { compatible rockchip,rk3568-pcie; reg 0x0 0xfe280000 0x0 0x10000; reg-names apb-base, mem-base; #address-cells 3; #size-cells 2; device_type pci; bus-range 0x0 0xf; interrupts GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH; interrupt-names sys; #interrupt-cells 1; num-lanes 2; clocks cru ACLK_PCIE30_MASTER, cru PCLK_PCIE30, cru ACLK_PCIE30_SLAVE, cru PCLK_PCIE30_PHY; clock-names aclk_mst, aclk_slv, aclk_dbi, pclk; resets cru SRST_PCIE30_POWER_UP, cru SRST_P_PCIE30; reset-names power, pipe; power-domains power RK3568_PD_PIPE; status disabled; };注意这里num-lanes 2对应x2模式。如果你设计只用x1那就要改成num-lanes 1并且硬件上也只接一组差分线。在板级设备树比如rk3568-evb.dts或你自己的板子dts里需要把PCIe3.0 x2使能并配置复位、供电等外部资源pcie3x2 { reset-gpios gpio0 RK_PC2 GPIO_ACTIVE_HIGH; vpcie3v3-supply vcc3v3_pcie; max-link-speed 3; num-lanes 2; status okay; };reset-gpiosPERST#对应的GPIO注意标识GPIO_ACTIVE_HIGH因为PERST#有效电平是低GPIO拉低表示复位拉高表示释放复位属于“active high”逻辑。vpcie3v3-supply指向3.3V供电的regulator节点内核会在链路训练前确保这个regulator被使能。max-link-speed 3限制最高链路速率3代表Gen3PCIe3.0。如果信号完整性不好可以先用2降到Gen2跑通基本功能再排查高速问题。3.2 PHY与组合PHY的配置PCIe3.0的PHY节点是单独配置的。RK3568在设备树中的PHY节点名为pcie30phy配置如下pcie30phy { status okay; };如果你的设计中PCIe3.0只用x1还需要指定这个PHY工作在x1模式此时要把pcie3x1节点也使能。但如果你使用x2那pcie3x1就必须disabledpcie3x1 { status disabled; };这里有个容易忽略的点PCIe3.0x2和PCIe3.0x1共用PHY的问题不仅影响设备树还影响uboot配置。如果uboot里已经把PCIe3.0x2打开了内核里就不能再开PCIe3.0x1否则PHY初始化会冲突导致两个控制器都枚举失败。调试时如果遇到“两个口都起不来”的情况先检查是不是这里打架了。另外如果用了PCIe2.0接口pcie2x1接WiFi模组这个控制器用的是Combphy2也就是和SATA0、USB3.0共用的那个组合PHY。设备树上也要配置对应的combphy节点并且需要确保SATA0和USB3.0没有同时占用这个PHY。在RK3568里这种复用关系很多一定要仔细看TRM里的PIN MUX和PHY分配表。3.3 内核Config与菜单配置设备树之外内核编译时必须把PCIe主机控制相关配置打开。我用的内核是Rockchip BSP 5.10分支下面这几个config项是必须确保开启的CONFIG_PCIy CONFIG_PCIE_ROCKCHIPy CONFIG_PCIE_ROCKCHIP_HOST_EPy CONFIG_PCI_MSIy CONFIG_PCIEPORTBUSy CONFIG_PCIEASPMy你可以通过make menuconfig确认Device Drivers --- PCI support --- PCI Express Port Bus support PCI Express ASPM control PCI host controller drivers --- Rockchip PCIe controller support其中CONFIG_PCIEASPM建议先开启但如果实际使用中遇到SSD省电导致掉盘可以再通过内核参数pcie_aspmoff来关闭ASPM排查。3.4 设备树常见参数说明参数含义典型值调试建议num-lanes链路通道数1 或 2与实际硬件走线一致max-link-speed最大链路速率3Gen3速率不达标时可先降到2reset-gpiosPERST#控制引脚GPIO确认GPIO复用和默认电平vpcie3v3-supply3.3V供电regulatorregulator节点确保regulator常开status节点使能状态okay/disableddisabled时不会初始化bus-rangePCIe总线号范围0x0 0xf一般不需要改设备树配置看起来简单但实际项目里最容易犯的错误是把reset-gpios的电平极性搞反。PERST#是低有效GPIO配置为GPIO_ACTIVE_HIGH意味着内核对GPIO做高电平操作时输出高、做低电平时输出低驱动会先拉低复位设备再拉高释放。如果这里写成了GPIO_ACTIVE_LOW那复位时序就完全反了链路肯定训练不起来。4. 启动阶段调试从uboot到Linux的命令行实战4.1 Uboot阶段确认PCIe初始化很多人忽略uboot阶段的调试直接进内核这其实是浪费了最快定位问题的机会。RK3568的uboot在初始化PCIe时会打印相关日志启动时留意 pci enum这个命令可以强制枚举PCIe总线。执行之后查看pci命令的输出 pci Scanning PCI devices... bus 0, device 0, function 0: Host controller bus 0, device 1, function 0: 144d:a808 Device 144d:a808144d:a808是三星NVMe SSD的Vendor ID/Device ID仅举例。如果你能看到类似输出说明uboot阶段PCIe链路已经训练成功问题基本不在物理层。如果pci enum之后看不到设备或者直接卡住那问题大概率出在硬件电路或uboot设备树配置上。此时回到第2章用示波器抓REFCLK和PERST#时序。需要注意的是uboot的设备树配置和内核是独立的Rockchip的uboot使用u-boot.dtsi或者u-boot.dts覆盖文件。如果你在uboot阶段启用了PCIe3.0x2记得uboot的配置里也要把PCIe3.0x1禁用和内核保持一致。4.2 内核日志分析抓重点内核启动时PCIe主控制器的日志默认是开启的关注这几个关键字dmesg | grep -i pcie正常情况下你会看到类似rockchip-pcie fe280000.pcie: host bridge /pciefe280000 ranges: rockchip-pcie fe280000.pcie: IO 0x000000fbe00000..0x000000fbefffff - 0x00000000000000 rockchip-pcie fe280000.pcie: MEM 0x000000f8000000..0x000000fbdfffff - 0x000000f8000000 rockchip-pcie fe280000.pcie: MEM 0x000000f0000000..0x000000f3ffffff - 0x000000f0000000 rockchip-pcie fe280000.pcie: phy link is up rockchip-pcie fe280000.pcie: link up, spee: Gen3, width: x2 rockchip-pcie fe280000.pcie: PCIe bus 0x0-0xf关键是这一行phy link is up和link up, spee: Gen3, width: x2。如果看到link is down或者卡在wait for link up说明LTSSM状态机没有进入L0状态物理层还有问题。另外还可以看PHY的日志dmesg | grep -i phy正常情况下PCIe30 PHY会打印初始化成功的信息。如果PHY没有正确初始化多半是设备树里PHY节点没使能或者PHY的时钟/电源没配好。4.3 Lspci与带宽状态检查进到Linux系统命令行后第一件事就是看lspcilspci -vvv重点看设备行01:00.0 Non-Volatile memory controller: Samsung Electronics Co Ltd Device a808 (rev 01) Subsystem: Samsung Electronics Co Ltd Device a801 Control: I/O Mem BusMaster SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx Status: Cap 66MHz- UDF- FastB2B- ParErr- DEVSELfast TAbort- TAbort- MAbort- SERR- PERR- INTx- Latency: 0, Cache Line Size: 64 bytes Interrupt: pin A routed to IRQ 77 Region 0: Memory at f0000000 (64-bit, non-prefetchable) [size16K] Region 1: Memory at f0004000 (64-bit, non-prefetchable) [size256] Capabilities: [40] Power Management version 3 Capabilities: [50] MSI: Enable Count1/32 Maskable- 64bit Capabilities: [70] Express (v2) Endpoint, MSI 00 LnkCap: Port #0, Speed 8GT/s, Width x4, ASPM not supported LnkSta: Speed 8GT/s (ok), Width x2 (downgraded)这里最关键的字段是LnkSta表示当前实际工作的链路速率和宽度。Speed 8GT/s就是PCIe3.0Width x2表示使用了2条lane。如果你看到Speed 2.5GT/s那就是跑在Gen1说明可能有训练降级的问题。如果担心lspci的显示还不够直观可以用setpci直接读链路状态寄存器setpci -s 01:00.0 0x52.w这个寄存器Link Status Register的bit[3:0]表示当前链路速度1代表Gen12.5GT/s2代表Gen25GT/s3代表Gen38GT/s。再配合查看内核的PCIe带宽统计cat /sys/bus/pci/devices/0000:01:00.0/max_link_speed cat /sys/bus/pci/devices/0000:01:00.0/current_link_speed要是current_link_speed一直不达标建议先回头查硬件尤其是REFCLK抖动和差分对走线质量。5. 常见故障与排查技巧实录5.1 链路训练失败LTSSM卡死现象uboot卡在PCIe枚举阶段内核日志显示wait for link up超时lspci什么都看不到。排查思路用示波器抓REFCLK正常情况下100MHz时钟应该稳定输出频率偏差在±300ppm以内。如果时钟都没有先查SoC的REFCLK引脚配置和时钟树。抓PERST#时序确认复位信号在电源稳定后至少100ms释放。我用示波器双通道同时抓过3.3V和PERST#发现复位比电源早释放了大约50ms这就是典型的时序问题。确认供电正常检查3.3V和1.8V/0.9V PHY供电的电压和纹波。曾经遇到过一次PHY供电的0.9V电压只有0.85V链路就一直训练不起来加了一颗大电容后恢复正常。检查AC耦合电容用万用表确认数据线上的电容是否有焊接问题断路和短路都会导致训练失败。这一层的排查动作做完80%的链路训练问题都能解决。5.2 设备枚举不出来或枚举为Unknown device现象链路训练显示link up了但lspci看不到设备或者看到Unknown device没有具体的厂商和型号。排查思路确认PCIe设备本身供电正常有些NVMe SSD需要额外的12V供电没供上就会导致设备不响应配置请求。检查设备树里的vpcie3v3-supply配置如果没有这个属性内核不会主动打开3.3V供电。实际调试时可以先用GPIO强制拉高或者用镊子短接触发确认供电没问题再改设备树。确认MSI中断配置正常。有些PCIe设备在MSI配置不正确时会枚举失败可以在设备树里加上msi-parent或者确认GIC的ITS配置。有一个细节RK3568的PCIe控制器默认使用intc作为中断控制器如果是用GIC的MSI需要检查msi-controller节点是否存在并且被正确引用。这个在Rockchip BSP里一般已经配好但如果你是自己裁剪的内核很容易漏掉。5.3 速率带宽不达标只能Gen1/Gen2现象链路能训练成功但LnkSta显示速度只有2.5GT/s或者5GT/s达不到Gen3。排查思路先看max-link-speed是不是设成了2或1如果是为了稳定性故意降速那就不是bug。如果max-link-speed 3还是降级大概率是信号完整性问题。用示波器看眼图PCIe Gen3对信号质量要求很高眼图闭合一般是布线或者阻抗不匹配导致的。检查REFCLK抖动。PCIe Gen3的参考时钟抖动容限非常严格如果REFCLK来自SoC的PLL且没有正确配置展频也可能导致训练降级。检查AC耦合电容的容值。PCIe规范要求0.075uF~0.2uF太小的电容会衰减信号幅度影响链路训练。建议直接用0.1uF0402封装。有个实际案例某块板子一开始只能训练到Gen2查了很久最后发现是PCIe3.0的差分走线在连接器附近过了一个很长的stub过孔导致信号反射严重。把走线优化后Gen3稳定运行。5.4 随机掉盘与高温问题现象系统运行正常ssd读写一段时间后突然消失重启后又恢复。排查思路优先怀疑供电。SSD在高负载下电流增大电源电压跌落会导致SSD控制器复位。用示波器监控SSD供电跑压力测试时观察电压跌落幅度。检查散热。NVMe SSD在高负载下发热严重尤其是工业级宽温盘如果散热没做好主控温度过高会主动关闭链路。这个可以通过sensors查看温度或者读SSD的SMART信息确认。检查ASPM设置。Linux内核默认会启用ASPM有些SSD在L1.2状态切换时存在bug会出现链路训练不稳定的问题。可以先在内核命令行加pcie_aspmoff测试如果问题消失那就是ASPM兼容性问题可以在设备树或者systemd服务里关闭ASPM。检查PCIe链路是否有误码。可以用iperf或者dd持续读写SSD同时用dmesg看有没有PCIe AER错误日志。如果有大量AER错误说明链路质量不达标需要回看硬件设计。5.5 与硬件工程师协同调试的建议这里的经验可能比技术更有价值。我在调试RK3568 PCIe时最大的体会是软件工程师不能只盯代码一定要主动参与硬件调试特别是在设计评审阶段。我的建议留测试点REFCLK、PERST#、3.3V、1.8V、0.9V每一个都留测试点。调试时不用费劲去焊飞线。用隔离电源如果怀疑电源干扰可以临时用外置稳压电源给SSD供电快速排除供电问题。先测阻抗PCB回来后第一时间让产线或者硬件工程师测一下关键走线的阻抗85Ω差分线如果实际只有70Ω那后续的问题就都不用猜了。互相配合看时序示波器抓到的时序波形要和设备树里的GPIO配置对照着看。硬件和软件对“复位有效”的理解很可能不一样对齐一下概念能省很多沟通成本。5.6 快速排查速查表现象优先检查项排查工具/命令链路完全训练失败REFCLK、PERST#、供电示波器、万用表链路训练成功但lspci为空设备树status、供电regulatordmesg、lspci只能Gen1/Gen2AC耦合电容、REFCLK抖动、走线阻抗lspci -vvv、setpci随机掉盘供电跌落、ASPM、散热示波器、dmesg枚举为Unknown deviceMSI配置、供电、复位lspci -vvv、dmesg6. 写在最后的调试体会项目收尾时回头看这块板子的PCIe3.0x2最终能稳定跑在Gen3 x2最关键的不是某个参数调对了而是从一开始就坚持“分层调试”的思路。物理层不确认不动软件uboot不过不进内核这种笨办法反而最省时间。另外提一句如果你用的是正点原子或者其他第三方开发板的RK3568底子它们提供的设备树和内核配置通常已经过验证但千万别直接拿去改产品因为板子的PCIe走线、供电方案、复位时序和你的实际项目完全不同。把开发板当参考设计方案可以但当标准答案用往往会踩更大的坑。如果将来做PCIe3.0相关项目可以在硬件设计阶段就把这篇文章里的检查清单丢给硬件工程师提前规避风险。调链路这件事前期的10分钟设计评审能抵后期的一周Debug。
网站建设高端定制企业官网