
先说结论这块板子的PCIe3.0x2最终跑到了8GT/s x2顺序读稳定在1.5GB/s以上。但过程远没有这么顺利——插上NVMe盘启动内核日志里连PCIe控制器都没有枚举第一反应是设备树写错了翻来覆去改了几天最后发现根因在硬件电路的PERST#复位时序上。从那之后我养成了一个习惯遇到PCIe问题先按“电源→时钟→复位→引脚复用→设备树”的顺序排查而不是一上来就怀疑软件。RK3568的PCIe3.0x2是很多嵌入式Linux项目的刚需接口常见的用法就是接M.2 NVMe SSD、5G模组或者PCIe转千兆网卡。这个控制器用的是Synopsys DesignWare IP驱动在Linux内核里对应rockchip-pcie设备树节点本质上是在告诉驱动“控制器在哪、有几条Lane、时钟复位怎么控制、引脚复用怎么切”。软件配置看起来不复杂但它和硬件设计的耦合度比I2C、SPI这类接口高得多——链路训练是物理层的事哪一环没做到位结果就是link不起来。这篇文章不是逐行分析TRM而是把从拿到原理图到最终跑通性能的完整过程拆开讲哪些硬件设计点必须先自查、设备树里x2模式到底要配置哪些内容、内核和U-Boot侧要打开什么选项、链路训练失败时怎么一步一步定位最后给出实际压测数据和我踩过的坑。1. 硬件底子决定调试天花板RK3568 PCIe3.0x2电路设计自查清先强调一个观点设备树里写的num-lanes 2、max-link-speed Gen3只是软件期望值。如果硬件设计本身有问题软件再怎么配链路协商结果也会默默降级甚至完全训练失败。所以我拿到一块新板子第一件事不是看内核日志而是翻原理图。1.1 电源轨PCIe PHY对纹波和瞬态跌落敏感RK3568 PCIe PHY需要一组0.85V左右的模拟电源PCIE_AVDD_0V85以及1.8V域的逻辑电源。这两路电源需要注意的点不一样0.85V这一路主要给PHY的高速收发器供电对纹波和瞬态响应很敏感。若纹波超过规范要求轻则链路协商速率从Gen3降到Gen2重则无故丢包、CRC错误频发。1.8V域给控制和接口逻辑供电电流需求没有0.85V那么大但同样要关注去耦电容布局。我在实际项目里踩过这样的坑0.85V这路的DC-DC芯片选型正常但输出端的反馈采样电阻走得离电感太近导致负载瞬变时电压跌落超过5%。PCIe在低温下测试没什么问题一跑高负载或温度升高就出现链路重训练。后来在靠近PHY的位置补了高容值MLCC问题明显好转。自查时关注三点电源芯片的峰值电流余量是否大于PCIe PHY的瞬态需求PCB上从电源芯片到PHY的过孔和铜皮载流是否足够PHY供电引脚的本地去耦电容是否按datasheet要求摆放一般有0.1uF、1uF、10uF组合。1.2 100MHz参考时钟差分阻抗和AC耦合电容不能想当然PCIe的参考时钟是100MHz差分时钟电平标准通常支持HCSL和LVDS。RK3568的REFCLK差分对一定要遵守PCIe的阻抗要求——PCIe数据线和时钟线的差分阻抗都是85欧姆不是90欧姆也不是100欧姆。这一点我特别想强调因为很多画过USB90欧姆或以太网100欧姆的工程师默认按100欧姆画结果链路也能link上但Gen3眼图裕量很差速率提不上去。另外参考时钟源与PCIe控制器之间的AC耦合电容不能省。PCIe规范要求在源端放置AC耦合电容典型值是0.1uF。走线时注意时钟差分对要保持等长且与其他高速信号尽量拉开间距。若是时钟buffer方案看buffer的时钟精度是否满足300MHz±300ppmPCIe需要的是100MHz时钟不同参考架构有一定差异查TRM确认就行。自查手段很简单示波器探头点REFCLK差分对验证频率是100MHz用眼图模式看交叉点电压和抖动。没有示波器时至少确认晶振/时钟芯片的型号和精度。1.3 PERST#复位时序最容易背锅的一环PCIe链路训练是在PERST#释放后开始的。规范要求电源稳定后等REFCLK稳定PERST#至少再保持低电平100us然后才能拉高释放。如果PERST#拉高太快PHY可能还没完成初始化链路训练就会失败。RK3568方案里常见的做法有两种一种是SoC的GPIO控制PERST#由驱动在初始化时拉高另一种是RC电路直接延时。我倾向于前一种调试灵活可以精确控制时序。但要注意如果PERST#被某个GPIO控制而这个GPIO在设备树里没有配成输出高电平或者被默认初始化成低电平那链路永远起不来。排查时用逻辑分析仪采样PERST#和REFCLK对照时序。很多问题都出在这RESET#上掌门在软件里被别的驱动抢先设置为低或者U-Boot阶段没释放。1.4 Lane分配与TX/RX方向接反的后果不只是没信号PCIe3.0x2通常对应Lane0和Lane1。控制器TX必须连接设备RX控制器RX连接设备TX这是常识但实际项目中翻过原理图真的遇到过某根差分对在封装里被交换导致RX和TX接反的情况。后果是链路状态一直卡在Detect或Polling阶段因为物理层没法完成对端检测。另外注意x2模式是否要求Lane0和Lane1同时使用RK3568的PCIe3.0控制器如果做x2两个lane都要接。如果只使用x1模式另一个lane可以悬空。硬件设计时若想跑x2但只接了一个lane链路协商宽度最高只能到x1。信号完整性方面PCIe Gen38GT/s对走线损耗、过孔stub长度、连接器质量都比较敏感。我在自己的项目checklist里写的是数据线尽量短同一lane的TX差分对和RX差分对等长控制在一个合理范围避免多余的过孔和直角走线。1.5 引脚复用SATA/USB3.0/PCIe经常共用物理引脚RK3568是典型的SoC多路复用架构PCIe信号和部分SATA、USB3.0信号可能共用引脚组。若硬件原理图把某个引脚接给了PCIe设备但软件还在设备树里使能了SATA控制器或者pinctrl里没有把引脚切换到PCIe功能结果就是接口完全不工作。这一条严格来说算软硬件配置问题但引脚复用错误在现象上很像硬件问题。排查时先在硬件层面确认原理图看这个接口是否和其他控制器共用引脚然后在设备树里关闭冲突的控制器并确保PCIe节点的pinctrl正确。我习惯把硬件自查结果整理成一张表方便交叉验证自查项期望值主要排查手段0.85V PHY电源纹波合理无瞬态跌落超限示波器、电源分析仪100MHz REFCLK频率和抖动符合规范示波器/眼图仪差分阻抗85欧姆差分尽量等长PCB设计检查、TDRPERST#时序电源和时钟稳定后延时释放逻辑分析仪TX/RX连接控制器RX对设备TX控制器TX对设备RX原理图审查、万用表引脚复用与SATA/USB3.0的复用无冲突原理图 设备树pinctrl硬件这些点确认一遍大约需要半天到一天。板上没有明显物理缺陷的前提下再往下走设备树就更有底气。2. 设备树不是玄学x2模式从节点属性到PHY初始化的完整映射硬件确认没问题以后才进入到设备树配置环节。RK3568的PCIe3.0x2在设备树里通常包含两个节点一个PCIe控制器节点一个PCIe PHY节点。两者任何一个状态不是“okay”驱动都不会正常初始化。2.1 PCIe控制器节点骨架先看懂SDK默认配置不同SDK版本写法和地址有差异但整体结构类似。下面是一段基于Rockchip官方SDK风格的示意dts实际以你手上的源码为准pcie3x2: pciefe280000 { compatible rockchip,rk3568-pcie; reg 0x0 0xfe280000 0x0 0x10000, /* dbi */ 0x0 0xf0000000 0x0 0x100000, /* apb? 或 config空间具体看SDK */ 0x0 0xf1000000 0x0 0x100000; reg-names dbi, apb, config; device_type pci; linux,pci-domain 0; bus-range 0x0 0xf; interrupts GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH, GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH, GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH, GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH; interrupt-names sys, pmc, msi, legacy; clocks cru ACLK_PCIE30X2_MST, cru ACLK_PCIE30X2_SLV, cru ACLK_PCIE30X2_DBI, cru PCLK_PCIE30X2; clock-names aclk_mst, aclk_slv, aclk_dbi, pclk; resets cru SRST_PCIE30X2_POWER_UP, cru SRST_PCIE30X2_PIPE, ... reset-names power, pipe, ...; num-lanes 2; max-link-speed 3; /* 3 表示 Gen3, 8GT/s */ pinctrl-names default; pinctrl-0 pcie30x2m0_pins; /* 按原理图选择m0或m1 */ status okay; }; pcie30phy: phyfe8a0000 { compatible rockchip,rk3568-pcie-phy; reg 0x0 0xfe8a0000 0x0 0x10000; clocks cru PCLK_PCIE_PHY; clock-names pclk; resets cru SRST_PCIE_PHY; reset-names phy; #phy-cells 0; status okay; };这段代码里面有几个属性很关键num-lanes决定Lane数量max-link-speed决定链路速率上限interrupt-names里的“msi”和“legacy”关系到MSI中断能否正常工作pinctrl-0负责把物理引脚从GPIO或其他复用功能切换到PCIe。2.2 num-lanes和max-link-speed写的只是“能力上限”num-lanes 2的作用是告诉驱动这个控制器最多支持2条Lane。最终协商出来的实际链路宽度是硬件和终端设备共同确定的即使这里写的是2如果对端设备只支持x1协商结果就是x1。max-link-speed的值对应PCIe速率1是2.5GT/s2是5GT/s3是8GT/s。RK3568的PCIe3.0控制器硬件支持Gen3所以通常配3。但是这个属性在某些SDK里可能缺省驱动会做兜底处理。我的建议是显式写出来逻辑更清晰。调试阶段有个技巧如果链路训练总是失败先把max-link-speed 1改成Gen1。Gen1速率低对信号完整性要求宽松若Gen1能稳定枚举大概率是Gen3眼图裕量不足而不是设备树本身写错。2.3 时钟和复位属性不只是让驱动时钟“转”起来PCIe控制器本质上是一个高速外设需要给它提供AHB/APB接口的工作时钟以及用于高速SerDes的Pipe时钟。设备树里用clocks和resets把这些依赖关系映射到CRUClock and Reset Unit的对应输出。调试时如果驱动probe报错说clock或reset获取失败用dmesg看具体是哪个时钟获取失败再对照CRU的dtsi确认节点名称是否一致。这类问题在SDK升级后容易出现因为CRU的宏定义可能变化设备树没同步更新。2.4 PHY节点Link训练的前置条件RK3568的PCIe PHY相对独立单独挂在PHY节点上。有些方案里PHY需要额外配置PLL、校准参数这些都封装在驱动里。设备树里能控制的不多重点是确保它的status okay且使用的时钟和复位资源没有被其他节点独占。另外注意#phy-cells的值RK3568 PCIe PHY一般是0表示PHY全部由控制器独占。如果#phy-cells 1控制器节点可能还需要通过phys和phy-names属性引用具体PHY通道。具体写法在SDK的dtsi里都能查到我给的建议是先用SDK默认的组合不要轻易改。2.5 写完设备树后确认“真的生效了”修改完设备树重新编译boot.img或dtb烧录启动后不要只看现象要确认配置确实进入了内核。最简单的办法# 查看设备树里的节点是否可用 ls /proc/device-tree/pciefe280000/ # 查看status属性值 cat /proc/device-tree/pciefe280000/status如果status不是“okay”说明板级dts里有节点将其覆盖或者你没改对文件。另一个常见问题是编译时使用了缓存的旧dtb烧录后设备树没更新这种情况我想很多人都遇到过。2.6 SATA/USB3.0复用冲突的设备树处理如果硬件上PCIe和SATA共用引脚设备树里需要主动关闭另一个控制器。例如在板级dts里加上sata0 { status disabled; };顺序问题也要注意如果PCIe和SATA在同一个pinctrl组里两者同时使能会导致驱动申请资源失败。关闭冲突节点后建议也检查一下内核日志里有没有对应的resource busy信息。3. 内核与Bootloader协同让PCIe控制器在启动初期就进入正确状态设备树配好不代表内核就能自动把PCIe跑起来。还得看内核编译选项、U-Boot阶段是否初始化过PCIe、MSI中断是否正常路由。这一节讲的是软件层面除了设备树之外还需要检查的几件事。3.1 内核Kconfig这些选项缺一不可RK3568 PCIe依赖的内核选项主要有几个CONFIG_PCIy CONFIG_PCIE_ROCKCHIPy CONFIG_PCI_MSIy CONFIG_PCIEPORTBUSy CONFIG_PCI_HOST_GENERICy 视SDK版本而定我把CONFIG_PCIE_ROCKCHIP编入内核而不是编成模块。原因很实际PCIe在启动早期就要枚举总线如果驱动是模块启动时rootfs还没挂载或者模块加载顺序不对PCIe设备可能已经错过枚举时机你会看到bus已经扫描过但没有设备。虽然部分场景下可以手动echo 1 /sys/bus/pci/rescan补救但不如直接编译进内核省心。用zcat /proc/config.gz | grep PCI可以快速确认这些选项是否生效。3.2 MSI中断NVMe设备经常依赖它MSIMessage Signaled Interrupt是PCIe设备向CPU发送中断的主要方式。NVMe协议强烈依赖MSI/MSI-X如果设备树里MSI中断配置不正确会出现“系统识别到了NVMe盘但一读写就卡死”的诡异现象。RK3568的设备树里MSI中断通常在控制器的interrupts属性中对应interrupt-names msi。如果你用的是设计较为特殊的RK3568板卡还需要确认GIC的msi-map或msi-parent是否指向正确的中断控制器。调试时用cat /proc/interrupts查看有没有对应的PCIe MSI中断计数在增加如果没有考虑是不是设备树里interrupt-map没配对。3.3 U-Boot阶段从NVMe启动时的双刃剑Rockchip的U-Boot支持PCIe初始化用于从NVMe SSD引导内核。如果项目不依赖NVMe启动我的建议是U-Boot里可以不做复杂初始化让内核干净地接管。但要注意如果U-Boot已经初始化了PCIe设备进入内核后驱动会尝试重新初始化个别设备在“二次初始化”时状态不好就会出现内核日志里找不到设备的情况。遇到这种情况先在U-Boot命令行里执行pci enum看看U-Boot能否扫描到设备。U-Boot能扫到而内核扫不到通常说明U-Boot初始化后把设备置入了一个特殊状态内核的复位流程没有把它拉回来。可以通过设置内核启动参数pcirealloc或pcinomsi来做交叉测试确定是不是资源分配或MSI问题。3.4 EP模式与RC模式别拿EP模式跑宿主设备RK3568的PCIe控制器同时支持RCRoot Complex和EPEndpoint两种模式。默认SDK配置一般用作RC设备也就是我们常说的“主板插槽”。如果你要做PCIe转接卡、或者把RK3568作为PCIe从设备需要修改设备树中相关属性变成EP模式——但这个话题和本文主线不同我只提一个点调试前先确认设备树里控制器的模式和你的使用场景一致。假如你拿的默认dts配置碰巧是EP模式插上NVMe盘后它只会等主机来枚举自己链路当然起不来。4. 链路训练失败的逐层排查别急着怀疑设备树先让LTSSM告诉你答案这是本文的重头戏。链路训练失败时内核日志往往只有一句话但它背后可能藏着完全不同的问题。我一般分五步走看日志定性、读LTSSM状态、查PHY、查时钟复位时序、用配置降级做二分。4.1 第一步从dmesg区分失败类别常见日志有三类控制器probe失败一般表现为rockchip-pcie fe280000.pcie: failed to initialize或failed to get clock。这种和链路训练无关是设备树资源/时钟/复位配置问题。链路训练超时典型日志是rockchip-pcie fe280000.pcie: PCIe link doesnt start。这是最常见的一种表示物理层一直没有进入L0状态。设备枚举失败链路已经link上但访问配置空间时出错比如pci 0000:01:00.0: BAR 0: no space for resource。这类问题一般出在地址窗口分配、BDF扫描顺序或设备端配置空间访问异常。用dmesg | grep -i pci看一遍基本能确定从哪一层开始查。4.2 第二步读LTSSM状态直接看卡在哪个阶段LTSSMLink Training and Status State Machine是PCIe物理层的核心状态机。链路训练失败时它的状态能直接告诉你在哪个环节断了。在RK3568上如果驱动编译时带了调试支持可以通过/sys/kernel/debug/pcie/.../ltssm这类接口读取。也可以手动读取控制器寄存器DesignWare IP的LTSSM状态一般能在一个固定偏移处读到具体偏移要对照TRM或内核源码dw-pcie的寄存器定义确认。LTSSM状态取值范围和含义参照PCIe规范一般低数值表示还在物理层初始状态高阶数值表示进入L0工作态。下面是我排查时常用的一张状态表LTSSM状态含义常见问题方向Detect物理层正在检测对端TX/RX接反、引脚复用错误、链路无设备Polling正在交换位级同步信号参考时钟问题、信号质量太差、PHY未锁定Configuration正在协商链路宽度和lane编号Lane映射错误、对端设备不支持配置L0正常工作状态无需排查Recovery从错误或低功耗恢复中信号完整性问题、电源抖动如果反复卡在Detect阶段优先查物理层示波器看REFCLK有没有、PERST是否释放、TX/RX是否接反。如果卡在Polling或Configuration多考虑信号质量和设备兼容性。4.3 第三步确认PHY状态和PLL锁定PHY没初始化好LTSSM同样可能卡在最开始的地方。RK3568 PHY驱动probe成功后会配置PLL并提供稳定时钟。排查时看dmesg里PHY相关日志比如rockchip-pcie-phy是否报错或者在驱动里增加对应寄存器打印确认PHY ready标志位被置位。如果PHY一直报错回到设备树检查PHY节点的时钟和复位是否完整。有些板子的PHY节点被其他程序或早于PCIe的控制逻辑复用导致驱动probe失败。4.4 第四步用示波器/逻辑分析仪验证REFCLK和PERST时序这一步是硬件问题定位的“实锤”环节。实测要点REFCLK频率是否稳定在100MHz差分摆幅是否符合设备端输入要求PERST#释放时刻是否在REFCLK稳定之后且满足延时要求用双通道示波器同时抓PERST#和REFCLK数一下时间差。我在一块返修板上就遇到过PERST#网络的RC电容贴错容值导致释放慢了好几毫秒看起来没什么问题但PCIe控制器等了超时都没等到设备准备好最终报link失败。4.5 第五步用降级配置做二分定位当所有物理检查都没发现明显问题时我习惯用“降级法”缩小范围把max-link-speed改为1Gen1判断是否是Gen3信号完整性问题把num-lanes改为1判断是否某一根Lane的硬件连接有问题如果Gen1 x1能稳定工作再逐步提升到Gen1 x2、Gen2 x2、Gen3 x2。每次修改后都要断电重启。原因在于PCIe PHY的PLL状态在上电后锁定如果只是软件reboot部分PHY寄存器仍然保留之前的状态可能掩盖问题。这个坑很隐蔽——我有一段时间总改设备树然后reboot链路死活起不来后来断电重新上电一切正常。4.6 常见错误日志与排查方向对照内核日志/现象可能原因优先排查方向PCIe link doesnt start链路训练超时PERST时序、REFCLK、TX/RX接线failed to request PCIe config space设备树reg-names写错对照SDK dtsicannot enable device电源/时钟没开或依赖缺失clocks、resets、pinctrl枚举后读写卡死MSI中断配置异常检查设备树msi相关属性协商速率只有Gen1信号完整性差/PHY配置不对眼图测试、检查AC耦合电容协商宽度只有x1某一根Lane没接好硬件连通性测试5. 上板实测确认链路速率、宽度与真实带宽的四件套设备能被识别只是第一步。我见过很多系统能识别NVMe盘但链路协商在Gen1 x1速度惨不忍睹。所以上板验证必须数据说话。5.1 lspci -vvv看LnkCap和LnkSta系统起来后先用lspci -vvv查看PCIe控制器和终端设备的链路能力与状态。# 查看总线和设备列表 lspci -tv # 查看链路详情 lspci -vvv重点关注输出里的这一段LnkCap: Port #0, Speed 8GT/s, Width x2 LnkSta: Speed 8GT/s, Width x2LnkCap是硬件能力上限LnkSta是实际协商结果。如果LnkSta显示Speed 2.5GT/s, Width x1说明链路没有跑到预期状态回到排查流程继续查。5.2 setpci和配置空间用底层方式验证状态lspci太方便但如果你想在设备树调优或驱动开发场景下快速探测可以用setpci直接读写PCI配置空间。链路状态寄存器一般位于PCIe扩展配置空间不同设备的偏移不同典型情况下链路状态在配置空间0x72位置Link Status Register可以通过setpci -s 00:00.0 0x72.w读取。但不同平台和控制器可能不一样我建议以lspci -xxx输出的原始数据为准来判断。在RK3568上调试时我更常用的是内核自带的一些接口# 查看PCIe控制器链路状态如果驱动支持 cat /sys/kernel/debug/pcie/*/link # 查看设备错误计数 cat /sys/kernel/debug/pcie/*/errors5.3 NVMe盘性能测试测出真实带宽链路协商正确还要验证数据传输是否稳定。用NVMe盘最直接# 简单看下顺序读速度 hdparm -t /dev/nvme0n1 # 用dd做大块读 dd if/dev/nvme0n1 of/dev/null bs1M count4096 # 更严谨的测试用fio fio --nameseqread --rwread --bs1M --size2G --numjobs1 \ --filename/dev/nvme0n1 --ioenginelibaio --direct1 --iodepth32PCIe Gen3 x2单向有效带宽的理论上限约1.97GB/s128b/130b编码实际用户数据加上协议开销会略低一点。我实测RK3568平台上NVMe顺序读在1.4-1.8GB/s都算正常顺序写在1.2-1.6GB/s。如果数值差太多比如只有400MB/s重点检查是否协商降级或者盘本身性能就那样。5.4 稳定性和错误计数高温/长时间压测必须做PCIe信号完整性问题最典型的特征就是“平时挺好跑一段时间就不行”。我会做一轮长时间压测比如fio持续读写30分钟到1小时同时观察有没有链路重训练表现为系统瞬间卡顿后恢复/sys/kernel/debug/pcie/*/errors里CRC错误计数是否增长芯片和SSD温度是否过高。如果SSD温度超过85℃还长时间高负载运行可能会出现热降速或链路不稳定。这也是硬件散热设计的一部分调试时容易被忽略。6. 我在这块板子上反复踩过的坑与最终落地的参数组合这一节写一些真实案例。这些坑不一定每个项目都会踩到但遇到时特别费时间我自己花了三四个晚上才理清楚。6.1 SATA和USB3.0的复用冲突让我以为硬件挂了第一版板子PCIe3.0x2接口一开始怎么都不工作连检测信号都看不到。我怀疑过原理图、怀疑过PCB焊接、怀疑过设备树最后发现是板级dts里SATA节点是enabled状态占用了和PCIe相同的引脚组。内核启动时SATA驱动先抢占了PHY引脚PCIe驱动再去申请pinctrl时只能失败。关闭SATA节点后PCIe一次成功。这个教训是拿到全新板卡时先全局搜索一遍dts里有没有和PCIe引脚冲突的节点再开调。6.2 Gen1 x2先排除设备端兼容性另一个板卡现象是插上NVMe盘能识别但只能协商到Gen2怎么调设备树都上不了Gen3。后来把同一个M.2插槽接到一台标准PC上测试发现这张SSD在这个PC上也只能跑到Gen2。原来是SSD固件的兼容性问题而不是RK3568的问题。这个案例说明遇到速率上不去时用一个已知在PC上能跑Gen3的设备做替换测试能帮你快速甩开“设备端本身有问题”这个变量。所以我建议调试时手边常备两块盘一块是经过多次验证的老牌Gen3 SSD兼容性好另一块是你要量产适配的SSD。分别测一遍交叉对比很能说明问题。6.3 低速模式是排查信号完整性最有效的手段有一次Gen3死活上不去用示波器看眼图发现PCIe时钟芯片输出的REFCLK抖动超标。当时没有更好更快的时钟源于是把max-link-speed降为2Gen2作为临时方案并在硬件下一版迭代中更换了时钟buffer。这个妥协在生产上有时候是必要的但一定要记录在案产品宣传里也得写清楚最高支持Gen2。6.4 最终落地的dts关键片段下面是一段以官方SDK为基础的示例包含我验证过的关键配置思路不是完整dts只展示核心属性pcie3x2 { num-lanes 2; max-link-speed 3; pinctrl-names default; pinctrl-0 pcie30x2m0_pins; reset-gpios gpio3 RK_PB5 GPIO_ACTIVE_LOW; /* PERST#, 按实际原理图调整 */ status okay; }; pcie30phy { status okay; }; /* 如果和SATA复用引脚必须在板级dts里关闭 */ sata0 { status disabled; }; sata1 { status disabled; };reset-gpios的写法不是所有SDK默认都有有些版本里叫phys或者由驱动内建逻辑控制具体看驱动代码。加了之后可以更灵活地控制PERST#时序尤其适合做链路恢复测试。6.5 编译内核时的坑CONFIG_PCIE_ROCKCHIP编成模块踩过的雷有一版测试固件我把CONFIG_PCIE_ROCKCHIPm结果启动后系统已经扫描完PCIe总线但驱动模块还没加载导致NVMe盘没出现。手动modprobe之后再rescan也能用但这种流程不适合量产固件。建议直接CONFIG_PCIE_ROCKCHIPy。另外如果项目同时使用了PCIe网卡还要打开对应的网卡驱动。RK3568上接Intel I210或RTL8111这类网卡比较常见确认对应的CONFIG_E1000E、CONFIG_R8169也是编译进去的。6.6 一个新板子回来后我的全流程检查单最后把流程串一遍这也是我现在带新人时的标准流程拿到原理图先翻电源、REFCLK、PERST#、Lane接线和引脚复用确认硬件设计没有明显问题对照原理图检查板级dts里的pinctrl和冲突节点确保SATA/USB3.0/PCIe复用正确编译烧录后dmesg | grep -i pci看控制器是否正常probe读LTSSM状态或看日志判断卡在物理层还是枚举层用降级配置Gen1 x1逐步升到Gen3 x2做二分定位全速稳定后跑一轮fio压测和错误计数检查记录数据归档。这套流程帮我解决过不少看似无解的PCIe问题。说句实在话PCIe调试难就难在“硬件现象”和“软件配置”交织在一起但只要你把每一层拆开验证老板催得再急也稳得住。我手头这块板子最终就是按照这套方法调通的现在看到插上NVMe盘直接秒识别、满速跑测试还挺有成就感的。希望这篇文章能帮你少走点弯路。