往期内容
本文章相关专栏往期内容,PCI/PCIe子系统专栏:
- 嵌入式系统的内存访问和总线通信机制解析、PCI/PCIe引入
- 深入解析非桥PCI设备的访问和配置方法
- PCI桥设备的访问方法、软件角度讲解PCIe设备的硬件结构
- 深入解析PCIe设备事务层与配置过程
- PCIe的三种路由方式
Uart子系统专栏:
- 专栏地址:Uart子系统
- Linux内核早期打印机制与RS485通信技术
– 末片,有专栏内容观看顺序interrupt子系统专栏:
- 专栏地址:interrupt子系统
- Linux 链式与层级中断控制器讲解:原理与驱动开发
– 末片,有专栏内容观看顺序pinctrl和gpio子系统专栏:
专栏地址:pinctrl和gpio子系统
编写虚拟的GPIO控制器的驱动程序:和pinctrl的交互使用
– 末片,有专栏内容观看顺序
input子系统专栏:
- 专栏地址:input子系统
- input角度:I2C触摸屏驱动分析和编写一个简单的I2C驱动程序
– 末片,有专栏内容观看顺序I2C子系统专栏:
- 专栏地址:IIC子系统
- 具体芯片的IIC控制器驱动程序分析:i2c-imx.c-优快云博客
– 末篇,有专栏内容观看顺序总线和设备树专栏:
- 专栏地址:总线和设备树
- 设备树与 Linux 内核设备驱动模型的整合-优快云博客
– 末篇,有专栏内容观看顺序
目录
1.PCI驱动程序框架
1.1 PCI驱动框架
在bus平台总线中,都知道Dev硬件设备树资源可以通过在设备树指定然后被内核读取存储进为platform_device中,也可以在.c文件中去指定好设备的资源让虚拟的总线平台去读取,这些都基于我们提前知道了设备的硬件资源。
但是对于真实的PCI设备,它的资源哪里的?我们比较难去知道接入在板子上的PCI设备是什么,显卡?声卡?网卡?因此需要去扫描接入在PCI接口上的PCI设备去读取到它的硬件资源。
对于PCI_Host和PCIe设备都有自己的驱动
- 首先针对PCI_Host(RC),RC的硬件设备资源可以通过在设备树中去进行指定,采用的虚拟的总线平台,当资源和驱动程序匹配后,会调用的RC驱动程序中的probe函数,probe函数会去识别扫描挂在PCIe/PCI接口上PCI设备,创建出一个pci_dev来指代设备,里面有其资源,这个pci_dev会被挂载PCI主桥上
- 而对于PCI设备,既然被识别到了获取到了信息,它也有自己的驱动,也就是pci_driver。 两者(pci_driver和pci_dev)类似RC(device和driver)挂在虚拟platform平台总线那样被挂在了RC下的总线平台上 。当pci_driver和pci_dev匹配后,同样也会去调用自己的probe函数,比如可以去初始化本身。
下面是更详细的流程介绍:
1. PCI Host (Root Complex, RC) 的驱动流程
a. 设备树描述
- 在嵌入式系统中,PCI Host的硬件资源通过设备树(Device Tree, DT)来描述。设备树中会指定PCI控制器(RC)的资源,如内存映射地址、IRQ信息、时钟等。
b. Platform总线
- PCI Host(RC)的驱动通常是基于平台设备(platform device)的,属于虚拟总线平台架构。设备树中的硬件信息会通过平台设备的框架传递给RC驱动。
- 当资源匹配成功后,平台驱动框架会调用RC驱动中的
probe
函数。c. RC驱动中的probe函数
probe
函数负责初始化Root Complex,并启动总线扫描。它会扫描连接到PCIe接口的所有设备,识别出挂载在RC下的PCIe/PCI设备。- 扫描过程会通过读取配置空间中的设备ID、功能号等信息,发现并初始化每一个设备。
- 对于每个扫描到的设备,会创建一个对应的
pci_dev
结构体,这个结构体包含了该设备的所有硬件资源、配置信息,以及挂载的父总线信息。pci_dev
最终会挂载到PCI主桥上(即RC),形成PCI设备拓扑树。2. PCIe设备的驱动流程
a. PCIe设备被识别
- 一旦PCI Host完成设备扫描,每个设备的配置信息(如Vendor ID, Device ID, Class Code等)就会存储在相应的
pci_dev
结构体中。- 这些信息可以用来匹配相应的设备驱动程序,即
pci_driver
。b. PCIe设备的驱动(pci_driver)
- PCI设备有自己的
pci_driver
驱动程序。这个驱动程序通过Vendor ID、Device ID或Class Code与pci_dev
进行匹配。- 类似于platform设备的驱动匹配机制,PCI设备的驱动也是通过PCI核心层自动匹配
pci_dev
和pci_driver
。c. pci_driver中的probe函数
- 当
pci_dev
和pci_driver
匹配成功后,PCI核心层会调用该PCI设备驱动中的probe
函数。probe
函数用于初始化设备,设置DMA,分配IO内存,配置寄存器等。该函数会利用pci_dev
结构体中的资源来完成这些初始化操作。d. 设备初始化
在
probe
函数中,驱动程序通常会:
- 读取和配置设备寄存器。
- 设置中断处理。
- 启动设备的DMA或内存映射。
- 启动设备的I/O功能,使设备可以正常工作。
3. PCIe设备和RC的交互
- 在整个过程中,PCI设备是挂载在RC下的。在设备被成功识别、匹配驱动并初始化后,它就可以通过RC访问主内存、发送和接收数据包。RC管理了所有PCI设备的地址映射和中断请求,确保各个设备的正常通信。
RC驱动通过设备树和平台总线平台架构来初始化,并通过扫描设备生成pci_dev
。
PCIe设备驱动(pci_driver)通过匹配pci_dev
,调用probe
函数对设备进行初始化,使设备可以正常工作并与RC通信。
1.2 回顾一下地址空间的配置
在PCI/PCIe设备的扫描和初始化过程中,设备申请的空间范围的基地址(Base Address Register, BAR)会在设备的配置过程中进行读取和写入。这个过程发生在PCIe总线扫描时,特别是在PCIe配置空间的初始化阶段。
1. PCIe总线扫描过程
- 在Root Complex (RC) 驱动的
probe
函数中,PCIe主桥会扫描总线上连接的所有设备。 - 每个设备都拥有一块标准的PCIe配置空间,其中包含了设备的Vendor ID、Device ID、Class Code、BARs等信息。扫描时,RC会通过配置事务读取每个设备的配置空间。
2. 读取和写入基地址寄存器(BAR)
- 每个PCIe设备的配置空间中包含几个基地址寄存器(Base Address Registers, BARs),这些寄存器用于告诉系统设备需要映射的内存空间或I/O地址空间的大小和位置。
- BAR寄存器是32位或64位的寄存器,用于指定设备的内存或I/O空间基地址。
3. 基地址的申请和写入
-
在扫描阶段,RC驱动会执行以下操作:
- 读取BAR寄存器的内容:初始时,驱动程序会读取设备的BAR寄存器来确定设备需要的地址空间大小。具体操作是写入
0xFFFFFFFF
到BAR中,然后读取BAR的值,从中可以得出设备所需的地址空间大小。 - 分配地址空间:根据设备的需求,RC会分配适当的物理地址范围(内存或I/O空间),以确保设备的地址空间不会与其他设备冲突。
- 写入BAR寄存器:RC驱动会将分配好的地址范围写入设备的BAR寄存器,从而为该设备分配实际的内存或I/O地址空间。
- 读取BAR寄存器的内容:初始时,驱动程序会读取设备的BAR寄存器来确定设备需要的地址空间大小。具体操作是写入
4. 完成设备初始化
- 通过写入BAR寄存器,设备的内存或I/O空间被映射到系统的地址空间中,操作系统或驱动程序可以通过这些地址访问设备的资源。
- 这一步完成后,设备的资源就已经可以正常使用,
pci_dev
结构体也会被初始化,包含设备的配置信息和资源描述。
扫描过程中会涉及设备申请空间范围的基地址的写入。这个过程是通过读取和写入BAR寄存器来完成的,用以分配和映射设备所需的内存或I/O空间。
2.RK3399_PCIe芯片手册解读之AXI总线
AXI相关:\协议\AXI\ug1037-vivado-axi-reference-guide.pdf
开发板资料:\芯片手册\RK3399 Rockchip RK3399TRM V1.3 Part2.pdf
2.1 连接情况
实际芯片中,CPU与外设之间的连接更加复杂,高速设备之间通过AXI总线连接。AXI总线总传输数据的双方分为Master和Slave,Master发起传输,Slave回应传输。Master和Slave是多对多的关系,它们之间读、写可以同时进行的,内部结构图如下:
实际系统中,CPU(作为AXI总线的Master)可以发起读写操作,而PCI控制器则通常作为Slave连接在AXI总线上,处理来自CPU或其他Master的请求,并通过PCI/PCIe总线与下游设备通信。这个结构允许CPU通过AXI总线间接与PCIe设备进行通信。
在实际系统中的连接:
- CPU和PCI控制器的关系:
CPU 作为 Master 发起对 PCIe 控制器(Host Bridge/RC)的访问。PCIe控制器作为 Slave 响应这些访问请求。通过 AXI 总线,CPU 会向 PCIe 控制器发送请求,然后控制器对接收到的请求进行翻译,最终传输到PCIe设备。 - AXI 总线结构:
上图可以看到典型的 AXI 总线连接结构。多个 Master 设备(如 CPU、DMA 控制器等)可以通过 Crossbar 连接到多个 Slave 设备(如 PCIe 控制器、存储设备等)。数据的传输是通过 AXI 总线上的多个信号通道完成的。对于读写操作,Master 设备发送地址和控制信号,Slave 设备接收请求并回应数据。 - PCI 控制器(RC/Host Bridge)下的 PCIe 设备:
PCIe 控制器(RC)管理下游设备。它将来自 AXI 总线的请求转化为 PCIe 总线标准,并与下游 PCIe 设备交互。在 PCIe 设备的配置过程中,CPU 会通过 AXI 总线发起配置请求,PCIe 控制器解析并转发到目标设备。此时,设备会返回其 BAR(Base Address Register)信息,确定内存映射地址空间。
因此,简而言之,CPU 是 Master,PCIe 控制器是 Slave。这种架构使得 CPU 可以通过 AXI 总线间接访问挂载在 PCIe 控制器下的设备。
2.2 PCI控制器
RK3399的PCIe控制器就是挂在AXI总线上,在RK3399芯片手册中可以看到:
- AWADDR:AXI总线的写地址通道地址线,简单理解就是CPU要写PCIe控制器时发出的地址线
- ARADDR :AXI总线的读地址通道地址线,简单理解就是CPU要读PCIe控制器时发出的地址线
2.3 五个通道
在AXI总线中,读写可以同时进行,有5个通道:
-
读:
- 读地址通道:传输读操作的地址
- 读数据通道:传输读到的数据
-
写:
- 写地址通道:传输写操作的地址
- 写数据通道:传输要写的数据
- 写响应通道:传输写操作的结果
通道名称 | 通道功能 | 数据流向 |
---|---|---|
read address | 读地址通道 | 主机->从机 |
read data | 读数据通道(包括数据通道和读响应通道) | 从机->主机 |
write address | 写地址通道 | 主机->从机 |
write data | 写数据通道 | 主机->从机 |
write response | 写响应通道 | 从机->主机 |
2.4 信号线
AXI总线和其他总线一样,具有很多的信号,其中包括全局信号、写地址通道信号、写数据通道信号、写响应通道信号、读地址通道信号、读数据通道信号、低功耗接口信号。丰富的信号集分布在不同的通道中,每个通道都负责特定的功能,以实现高效的数据传输。
信号 | AXI4 | AXI4-Lite |
---|---|---|
AWADDR | 写地址通道:地址线,最多可达64位 | 写地址通道:地址线,最多可达64位 |
WDATA | 写数据通道:数据线,32~1024位 | 写数据通道:数据线,32位 |
ARADDR | 读地址通道:地址线,最多可达64位 | 读地址通道:地址线,最多可达64位 |
RDATA | 读数据通道:数据线,32~1024位 | 写数据通道:数据线,32位 |
AXI总线(AXI4 和 AXI4-Lite)拥有丰富的信号集,分布在不同的通道中,每个通道都负责特定的功能,以实现高效的数据传输。下面列出了除你提到的 AWADDR(写地址通道)、WDATA(写数据通道)、ARADDR(读地址通道)、RDATA(读数据通道)以外的其他重要信号,并按照通道划分。下面是除了上面信号的其它信号,按照通道划分:
1. 全局信号
这些信号在AXI协议中是全局信号,负责时钟和复位管理:
- ACLK:时钟信号,所有的 AXI 信号都基于这个时钟。
- ARESETn:复位信号,低电平有效。用于系统复位。
2. 写地址通道信号
写地址通道用于发送写操作的地址和控制信息:
- AWVALID:写地址有效信号,表示地址传输有效。当 Master 准备好写地址时,将其置为高。
- AWREADY:写地址就绪信号,表示 Slave 准备好接收写地址。为高时,Slave 可以接受地址。
- AWID(可选,AXI4 独有):标识 ID,用于区分不同的写事务。
- AWLEN:突发长度,指定突发传输中传输的数据数量。
- AWSIZE:突发传输的宽度,表示每次突发传输的数据大小(如字节、半字、字等)。
- AWBURST:突发类型,定义突发传输是固定地址、递增地址还是包装突发。
- AWLOCK:锁信号,表示是否需要独占访问资源。
- AWCACHE:缓存类型信号,指示访问类型(缓存、缓冲等)。
- AWPROT:保护类型信号,用于定义访问的权限和安全属性。
- AWQOS:服务质量信号,用于指示 QoS(服务质量)等级。
3. 写数据通道信号
写数据通道用于传输写操作的数据:
- WVALID:写数据有效信号,表示数据传输有效。当 Master 准备好写数据时,将其置为高。
- WREADY:写数据就绪信号,表示 Slave 准备好接收写数据。为高时,Slave 可以接收数据。
- WSTRB:写选通(Byte strobe),用于标识哪个字节有效。每一位对应一个数据字节的有效性(1 表示有效)。
- WLAST:突发传输中的最后一个数据信号。Master 通过该信号告知 Slave 突发结束。
4. 写响应通道信号
写响应通道用于向 Master 返回写操作的响应:
- BVALID:写响应有效信号,表示写响应有效。Slave 通过该信号告知 Master 写操作完成。
- BREADY:写响应就绪信号,表示 Master 准备好接收写响应。
- BID(可选,AXI4 独有):写响应 ID,用于与 AWID 匹配,确保写响应对应正确的事务。
- BRESP:写响应,表示写操作的状态(如 OKAY、EXOKAY、SLVERR 或 DECERR)。
5. 读地址通道信号
读地址通道用于传输读操作的地址和控制信息:
- ARVALID:读地址有效信号,表示读地址传输有效。当 Master 准备好读地址时,将其置为高。
- ARREADY:读地址就绪信号,表示 Slave 准备好接收读地址。为高时,Slave 可以接受地址。
- ARID(可选,AXI4 独有):标识 ID,用于区分不同的读事务。
- ARLEN:突发长度,指定突发传输中传输的数据数量。
- ARSIZE:突发传输的宽度,表示每次突发传输的数据大小。
- ARBURST:突发类型,定义突发传输是固定地址、递增地址还是包装突发。
- ARLOCK:锁信号,表示是否需要独占访问资源。
- ARCACHE:缓存类型信号,指示访问类型(缓存、缓冲等)。
- ARPROT:保护类型信号,用于定义访问的权限和安全属性。
- ARQOS:服务质量信号,用于指示 QoS 等级。
6. 读数据通道信号
读数据通道用于从 Slave 传输数据到 Master:
- RVALID:读数据有效信号,表示读数据传输有效。Slave 准备好传输数据时将其置为高。
- RREADY:读数据就绪信号,表示 Master 准备好接收数据。
- RID(可选,AXI4 独有):读数据 ID,用于与 ARID 匹配,确保读数据对应正确的事务。
- RRESP:读响应,表示读操作的状态(如 OKAY、EXOKAY、SLVERR 或 DECERR)。
- RLAST:突发传输中的最后一个数据信号。Slave 通过该信号告知 Master 突发结束。
7. 低功耗接口信号(可选)
AXI 协议中还支持低功耗信号,用于电源管理:
- CSYSREQ:系统请求信号,表示进入低功耗模式的请求。
- CSYSACK:系统响应信号,表示系统已进入低功耗模式。
- CACTIVE:系统活动信号,表示系统仍处于活动状态。
这些信号共同构成了 AXI4 和 AXI4-Lite 总线系统,它们在不同的通道中协作,实现数据传输的复杂过程。AXI4 支持高吞吐量和高带宽,适用于复杂的高速设备,而 AXI4-Lite 则简化了设计,适用于对带宽需求较低的设备。