六、RK3399_PCIe芯片手册解读+PCIe 配置空间、内存/IO空间读写机制

1. AXI总线

1.1 连接方式

我们一直使用这个图来简化CPU与外设之间的连接:

实际芯片中,CPU与外设之间的连接更加复杂,高速设备之间通过AXI总线连接 。AXI总线总传输数据的双方分为Master和Slave,Master发起传输,Slave回应传输。 Master和Slave是多对多的关系,它们之间读、写可以同时进行的,内部结构图如下:

1.2 五个通道

在AXI总线中,读写可以同时进行,有5个通道:

  • 读:
    • 读地址通道:传输读操作的地址
    • 读数据通道:传输读到的数据
  • 写:
    • 写地址通道:传输写操作的地址
    • 写数据通道:传输要写的数据
    • 写响应通道:传输写操作的结果

|----------------|---------------------|----------|
| 通道名称 | 通道功能 | 数据流向 |
| read address | 读地址通道 | 主机->从机 |
| read data | 读数据通道(包括数据通道和读响应通道) | 从机->主机 |
| write address | 写地址通道 | 主机->从机 |
| write data | 写数据通道 | 主机->从机 |
| write response | 写响应通道 | 从机->主机 |

1.3 信号线

我们只列出本节视频关心的信号线:

|--------|---------------------|-------------------|
| 信号 | AXI4 | AXI4-Lite |
| AWADDR | 写地址通道:地址线,最多可达64位 | 写地址通道:地址线,最多可达64位 |
| WDATA | 写数据通道:数据线,32~1024位 | 写数据通道:数据线,32位 |
| ARADDR | 读地址通道:地址线,最多可达64位 | 读地址通道:地址线,最多可达64位 |
| RDATA | 读数据通道:数据线,32~1024位 | 写数据通道:数据线,32位 |

1.4 PCIe控制器

RK3399的PCIe控制器就是挂在AXI总线上,在芯片手册中可以看到:

  • AWADDR:AXI总线的写地址通道地址线,简单理解:CPU要写PCIe控制器时发出的地址线
  • ARADDR :AXI总线的读地址通道地址线,简单理解:CPU要读PCIe控制器时发出的地址线

2. 地址空间和寄存器介绍

2.1 想达到的目的

使用PCIe时,我们编程时想达到这个目的:

  • CPU读写某个地址,就可以读写某个PCIe设备的配置空间:
  • CPU读写某个地址,就可以读写某个PCIe设备的内存、寄存器:

简单地说,就是把CPU发出的addr,转换为右边的TLP头部:PCI地址、头部的其他信息。

这涉及两部分:

  • 怎么把CPU地址转换为PCI地址
  • 怎么提供TLP头部信息中的其他部分

2.2 地址空间

RK3399访问PCIe控制器时,CPU地址空间可以分为:

  • Client Register Set:地址范围 0xFD000000~0xFD7FFFFF,比如选择PCIe协议的版本(Gen1/Gen2)、电源控制等
  • Core Register Set :地址范围 0xFD800000~0xFDFFFFFF,所谓核心寄存器就是用来进行设置地址映射的寄存器等
  • Region 0:0xF8000000~0xF9FFFFFF , 32MB,如果cpu_addr落在这片地址,表示将用于读写外接PCIe设备的配置空间---BAR
  • Region 1:0xFA000000~0xFA0FFFFF,1MB,如果cpu_addr落在这片地址,表示这个地址将用于读写pcie设备的内存空间/IO空间(地址转换)
  • Region 2:0xFA100000~0xFA1FFFFF,1MB,用于地址转换
  • ......
  • Region 32:0xFBF00000~0xFBFFFFFF,1MB,用于地址转换

其中Region 0大小为32MBRegion1~31大小分别为1MB

CPU访问Region 0的地址时,将会导致PCIe控制器发出读写配置空间的TLP。

CPU访问Region 1~32的地址时,将会导致PCIe控制器发出读写内存、IO空间的TLP。

2.3 寄存器介绍

CPU访问一个地址,导致PCIe控制器发出TLP。TLP里含有PCIe地址、其他信息。

这些寄存器必定涉及这2部分:

  • 地址转换:把CPU地址转换为PCIe地址
  • 提供TLP的其他信息

Region0、Region1~32,每个Region都有类似的寄存器。

Region0可以用于读写配置空间;Region1~32,可以用于读写内存空间、可以用于读写IO空间,还可以用于读写消息。这由Region对应的寄存器决定。

每个Region都有一样寄存器,以Region 0为例,有6个寄存器:

CPU访问某个Region时,它是想干嘛?

  • 读写配置空间、发出对应TLP?
  • 读写内存空间、发出对应TLP?
  • 读写IO空间、发出对应TLP?
  • 读写消息、发出对应TLP?

到底是发出哪种TLP ,由Region对应的ob_desc0寄存器决定:

|---------------------|---------------------------------|
| ob_desc0[3:0] | 作用 |
| 1010 | 发出的TLP用于访问Type 0的配置空间 |
| 1011 | 发出的TLP用于访问Type 1的配置空间 |
| 0010 | 发出的TLP用于读写内存空间 |
| 0110 | 发出的TLP用于读写IO空间 |
| 1100 | 发出的TLP是"Normal Message" |
| 1101 | 发出的TLP是"Vendor-Defined Message" |

CPU访问某个Region时,最终都是要发出TLP,TLP的内容怎么确定?

  • 地址信息:ob_addr0/1把CPU地址转换为PCIe地址,提供TLP里面的地址信息
  • 其他信息:ob_desc0/1/2/3提供TLP的其他信息

2.3.1 用于配置空间

Region0一般用于读写配置空间,它对应的寄存器如下(每个region都有类似的寄存器):

2.3.2 用于内存和IO

3. 访问示例

3.1 配置空间读写示例

要读写设备的配置空间,首先要定位:Bus/Dev/Function/Reg:

怎么发出这些"Bus/Dev/Function/Register"信息?如下图所示:

当Region 0的寄存器ob_desc0[3:0]被配置为读写配置空间时, CPU发出Region 0的地址,地址里面隐含有这些信息:

  • Bus:cpu_addr[27:20]
  • Dev:cpu_addr[19:15]
  • Fun:cpu_addr[14:12]
  • Reg:cpu_addr[11:0]

使用过程步骤如下。

3.1.1 配置Region 0用于读写配置空间

3.1.2 配置Region 0地址转换

比如可以设置bit[5:0]为27(add0[5:0]表示从cpu_addr中提取多少位来构造pci_addr),意味着cpu_addr[27:0]这28条地址线都会传入TLP。

3.1.3 CPU读写Region 0的地址

Region 0的地址范围是:0xF8000000~0xF9FFFFFF。

CPU想访问这个设备:Bus=bus,Dev=dev,Fun=fun,Reg=reg,那么CPU读写这个地址即可:

0xF8000000 + (bus<<20) | (dev<<15) | (fun<<12) | (reg)

3.2 MEM/IO读写示例

3.2.1 配置Region 1用于内存读写

3.2.2 配置Region 1地址转换

addr0、addr1寄存器里保存的是PCIe地址,也就是CPU发出这个Region的CPU地址后,将会转换为某个PCI地址。

怎么转换?由addr0、addr1决定。

Region 1的CPU地址范围是:0xFA000000~0xFA0FFFFF,是1M空间。

我们一般会让PCI地址等于CPU地址(也可以设置成不一样),所以这样设置:

  • addr0:
    • 5:0\]等于19,表示CPU_ADDR\[19:0\]共20位地址传入TLP

  • addr1:设置为0

如上设置后,CPU读写地址时0xFA0?????,就会转换为PCI地址:0xFA0?????,转换过程如下:

复制代码
pci_addr = cpu_addr[19:0] | (addr0[31:20] << 20) | (addr1<<32)
         = 0x????? + (0xFA0 << 20) | (0 << 32)
         = 0xFA0?????

4. outbound vs inbound

4.1 Outbound(CPU → PCIe 设备)

目的:CPU通过 PCIe 控制器发起对 PCIe 设备的读写操作时,需要将SoC 地址转换为 PCIe TLP(事务层包)中的地址。

🔹 流程:

  1. CPU 发起请求:通过 AXI 总线发出一个地址(例如 0x8000_0000)。
  2. PCIe 控制器拦截:该地址落在 Outbound 地址窗口内。
  3. 地址转换:
    1. 根据 addr0****寄存器的配置( **[5:0]****表示"传递的地址位数"),**决定从 AXI 地址中提取多少位用于构造 PCIe 地址。
    2. 剩余的高位用于构造 PCIe 路由信息:
      • [31:0]:保留
      • [5:0]:传递的地址位数(至生成 TLP:少为 8)
      • [11:8]:Extended Register Number(传给 AXI2HAL)
      • [14:12]:Function Number(或 ARI ID[2:0])
      • [19:15]:Device Number(或 ARI ID[7:3])
      • [27:20]:Bus Number
  4. 生成 TLP:
    1. 使用转换后的 Bus/Device/Function + 地址 构造 PCIe TLP。
    2. 发送到 PCIe 总线上。

🔹示例(假设 addr0[5:0] = 12):

  • 表示传递 12 位地址。
  • 如果 AXI 地址是 0x8000_1234
    • 低 12 位(0x234)作为 PCIe 地址的一部分。
    • 高位用于填充 Bus/Device/Function。

4.2 Inbound(PCIe设备 → CPU)

目的:PCIe 设备发起对 CPU 内存的 DMA 读写时,需要将 PCIe TLP 中的地址转换为 SoC 内存地址。

🔹 流程:

  1. PCIe 设备发起请求:发送一个 TLP,包含目标地址(PCIe 地址空间)。
  2. PCIe 控制器拦截:该地址落在 Inbound 地址窗口内。
  3. 地址转换:
    1. 使用Inbound ATU(地址转换单元) 将PCIe地址映射到SoC内存地址
    2. 通常通过配置基址寄存器(BAR)和转换偏移 实现。
  4. 转发到AXI 总线:
    1. 转换后的地址通过AXI总线访问 SoC 内存。
    2. 完成 DMA 读写。

4.3 关键寄存器说明

|---------|-----------------------------------------------------------------------------------------------------------------------------------------------|
| 寄存器 | 说明 |
| desc3 | 保留 |
| desc2 | 保留 |
| desc1 | PCIe 头描述符高 32 位 |
| desc0 | PCIe 头描述符低 32 位 |
| ddr1 | 应写 0 |
| ddr0 | 地址转换控制字段 : - [27:20] :Bus Number - [19:15] :Device Number - [14:12] :Function Number - [11:8] :扩展寄存器号 - [5:0]传递的地址位数(关键!) |

4.4 总结对比

|--------------|----------|--------|-----------------------------|
| 方向 | 触发者 | 目标 | 转换关键 |
| Outbound | CPU(SoC) | PCIe设备 | addr0[5:0] 控制地址位数,高位用于路由 |
| Inbound | PCIe设备 | CPU内存 | 通过BAR + 偏移映射,由Inbound ATU完成 |

相关推荐
CodeCraft Studio3 天前
【案例分享】Parasoft助力智能车辆嵌入式软件符合FDA认证和IEC 62304标准
嵌入式软件·parasoft·嵌入式测试·软件合规·c/c++test·代码级合规
小程同学>o<6 天前
嵌入式之ARM体系与架构面试题(四)通信协议篇
arm开发·笔记·架构·嵌入式软件·通信协议·面试题库
小程同学>o<8 天前
嵌入式之ARM体系与架构面试题(三)ARM中断与异常
arm开发·架构·异常·嵌入式软件·中断
小程同学>o<8 天前
嵌入式之ARM体系与架构面试题(二)ARM处理器篇
arm开发·面试·架构·嵌入式软件·嵌入式面试·嵌入式面试资料
小程同学>o<9 天前
嵌入式之C语言面试题(一)基本概念及其它问答题
c语言·面试·职场和发展·嵌入式软件·c语言面试
smalming11 天前
专题-图形界面之ARM2D
嵌入式软件
轻微的风格艾丝凡17 天前
嵌入式定时器计时技巧:用有符号数省略溢出判断的底层逻辑与实践
数据库·算法·dsp开发·嵌入式软件
SoveTingღ17 天前
【C语言】什么是野指针?
c语言·指针·嵌入式软件
农民真快落19 天前
【操作系统】手撸xv6操作系统——types.h/param.h/memlayout.h/riscv.h/defs.h头文件解析
操作系统·risc-v·嵌入式软件·xv6