1. RK3568 PCIe 硬件架构概述

各位同学好,我是老李。做嵌入式Linux驱动开发十几年了,RK3568这颗芯片我摸过不少。今天咱们开始第一讲——PCIe硬件架构。说白了,就是看看RK3568肚子里那个PCIe控制器到底长什么样,怎么工作的。

我个人习惯,做驱动之前一定要先把硬件摸透。你想想看,连硬件怎么跑的你都不清楚,写出来的驱动能稳吗?

1.1 控制器配置能力:Gen3x2 vs Gen2x1

RK3568内部集成了一个PCIe控制器,但它有两种工作模式:

模式 通道数 单通道速率 总带宽 典型场景
Gen3 x2 2条 8 GT/s ~16 GT/s NVMe SSD、高速网卡
Gen2 x1 1条 5 GT/s ~5 GT/s WiFi模块、低速外设

这里有个关键点:两种模式不能同时用。你只能在设备树里选一种。我在项目中遇到过,有人想同时接NVMe和WiFi,结果发现控制器只能选一种配置——嗯,踩坑了才知道。

注意:Gen3 x2模式下,PCB走线必须做阻抗匹配(85Ω差分对),长度差控制在5mil以内。否则链路训练会失败,我吃过这个亏。

1.2 内部DMA引擎

PCIe控制器内部集成了一个DMA引擎,负责搬运数据。它支持两种传输方式:

  • PIO模式:CPU直接读写PCIe配置空间和BAR空间。适合小数据量,比如配置寄存器。
  • DMA模式:硬件自动搬运,不占CPU。适合大数据量,比如NVMe读写。

DMA引擎的核心寄存器组如下:

// DMA控制寄存器(基地址偏移0x1000)
#define DMA_CTRL            0x00
#define DMA_SRC_ADDR        0x04
#define DMA_DST_ADDR        0x08
#define DMA_TRANS_SIZE      0x0C
#define DMA_STATUS          0x10

我个人建议,能用DMA就别用PIO。之前有个项目,用PIO传4K数据,CPU占用率直接飙到80%。换成DMA后,降到5%不到。

1.3 MSI中断控制器

RK3568的PCIe控制器支持MSI(Message Signaled Interrupts),也就是消息信号中断。它和传统的中断引脚(INTx)不一样:

特性 MSI INTx
中断方式 写内存消息 拉低引脚电平
中断向量数 最多32个 4个(A/B/C/D)
共享中断 不支持 支持
性能 高(无轮询) 低(需电平检测)

为什么MSI性能更好?因为它直接写内存触发中断,不需要CPU去检测引脚电平。我曾经在调试NVMe驱动时,发现中断响应延迟不稳定,后来查出来是INTx共享中断导致的。换成MSI后,延迟稳定在微秒级。

小技巧:在设备树中使能MSI,需要在PCIe节点中添加 msi-parent = <&gic>。否则内核会回退到INTx。

1.4 PHY层初始化流程

PHY层是PCIe的物理层,负责信号的串并转换和链路训练。初始化流程大致如下:

  1. 上电复位:PHY进入复位状态,等待电源稳定。
  2. PLL锁定:内部锁相环锁定参考时钟(100MHz)。
  3. 链路训练:发送训练序列(TS1/TS2),协商速率和通道数。
  4. 链路确认:双方确认链路宽度和速率,进入L0状态。

这里我画了一张流程图,帮你理清整个初始化过程:

RK3568 PCIe PHY初始化流程 RK3568 PCIe PHY初始化流程 上电复位 PLL锁定 链路训练 链路确认(L0) 说明:链路训练失败会回退到Gen2或x1模式,甚至完全断开 常见原因:时钟不稳、阻抗不匹配、电源纹波过大

链路训练这一步最容易出问题。我曾经调试一块板子,PCIe死活训练不过去。查了两天,最后发现是参考时钟的100MHz晶振精度不够,换了±25ppm的晶振就好了。

核心要点:
  • RK3568 PCIe控制器支持Gen3 x2和Gen2 x1两种模式,二选一
  • DMA引擎是性能关键,大数据传输必须用DMA
  • MSI中断比INTx更高效,优先使用
  • PHY初始化中链路训练是最大坑点,注意硬件设计质量