4. Linux SPI 子系统架构:SPI 核心层、SPI 控制器驱动层、SPI 设备驱动层、SPI 设备树绑定

在嵌入式 Linux 系统中,SPI(Serial Peripheral Interface)子系统采用经典的分层架构设计,将协议处理、硬件控制与设备逻辑解耦。理解这一架构是全志 T113 SPI Flash 驱动适配与性能调优的基础。本章从整体框架出发,逐层剖析 SPI 核心层、控制器驱动层、设备驱动层以及设备树绑定的职责与交互机制。

架构核心思想: Linux SPI 子系统通过分层抽象,使得 SPI 控制器驱动(硬件相关)与 SPI 设备驱动(协议相关)可以独立开发与维护。设备树则充当硬件拓扑的描述语言,将两者在运行时绑定。

4.1 SPI 子系统整体分层架构

SPI 子系统从上到下分为三层:SPI 设备驱动层、SPI 核心层、SPI 控制器驱动层。设备树通过描述 SPI 控制器与从设备的连接关系,驱动核心层在初始化时完成匹配与注册。

Linux SPI 子系统分层架构 用户空间应用程序(用户态 SPI 访问 /dev/spidev* 或 MTD 层) SPI 设备驱动层 spi_driver / SPI Flash 驱动 (m25p80.c) / 通用 SPI 设备驱动 SPI 核心层 (spi.c / spi-mem.c) 总线注册 / 设备与驱动匹配 / 数据传输队列 / SPI-MEM 抽象 SPI 控制器驱动层 全志 T113 SPI 控制器驱动 (spi-sunxi.c) / 硬件寄存器操作 硬件层:全志 T113 SPI 控制器 + SPI NOR Flash (W25Q128/SFUD) 设备树绑定
关键理解: 在全志 T113 平台上,SPI Flash 驱动通常位于设备驱动层(如 m25p80.c 或 spi-nor 框架),通过 SPI 核心层调用控制器驱动层提供的硬件接口完成数据收发。设备树文件(.dts)中的 spi0 节点描述了控制器基地址、时钟、DMA 以及连接的 Flash 芯片信息。

4.2 SPI 核心层(SPI Core)

SPI 核心层位于 drivers/spi/spi.c 中,是整个子系统的中枢。它负责以下关键功能:

  • 总线注册与管理: 注册 SPI 总线类型(spi_bus_type),管理所有 SPI 控制器与设备。
  • 设备与驱动匹配: 当设备树解析出 SPI 设备节点后,核心层根据 compatible 属性匹配对应的 spi_driver。
  • 数据传输队列: 提供 spi_async()、spi_sync() 接口,管理消息队列并调度控制器驱动完成传输。
  • SPI-MEM 抽象层: 针对 SPI 存储设备(如 NOR Flash)提供 spi_mem_ops 接口,简化读写操作。
核心接口/数据结构 所在文件 功能描述
struct spi_controller spi.h 代表一个 SPI 控制器,包含传输方法、DMA 配置、时钟等
struct spi_device spi.h 代表一个 SPI 从设备,包含模式、速度、字长等参数
struct spi_message spi.h 一次 SPI 传输的完整描述,包含多个 spi_transfer
spi_register_controller() spi.c 控制器驱动调用,将控制器注册到核心层
spi_sync() spi.c 同步阻塞式 SPI 数据传输
spi_async() spi.c 异步非阻塞式 SPI 数据传输
性能提示: 在 SPI Flash 读写场景中,核心层的消息队列调度直接影响吞吐量。全志 T113 平台建议使用 spi-mem 接口(spi_mem_exec_op()),它针对存储设备优化了命令/地址/数据阶段的组合传输,减少消息拆分开销。

4.3 SPI 控制器驱动层

控制器驱动层直接操作硬件寄存器,实现 SPI 总线的时序控制。对于全志 T113 平台,控制器驱动通常位于 drivers/spi/spi-sunxi.c(或类似命名)。

控制器驱动需要实现的核心回调函数:

  • master_transfer() / transfer_one_message():执行单个 SPI 消息的传输。
  • setup():配置 SPI 设备的模式(CPOL/CPHA)、位宽、时钟频率。
  • prepare_message() / unprepare_message():传输前后的准备与清理。
  • can_dma():判断当前传输是否适合使用 DMA。
全志 T113 SPI 控制器驱动传输流程 SPI 核心层调用 transfer_one_message 解析 spi_message 中的 transfer 列表 判断 can_dma() → 选择 PIO 或 DMA 模式 操作 SPI 控制器寄存器(FIFO/CS/CLK/DMA)
全志 T113 控制器特性: T113 的 SPI 控制器支持 4 个片选、8/16/32 位数据宽度、内置 64 字节 TX/RX FIFO,并支持硬件 DMA 传输。在调优时,合理配置 SPI 时钟频率(通常 50MHz~100MHz)和启用 DMA 是提升读写性能的关键。

4.4 SPI 设备驱动层

设备驱动层实现具体的 SPI 设备协议。对于 SPI NOR Flash,内核提供了 drivers/mtd/spi-nor/ 框架,其中 spi-nor.c 和 m25p80.c 是核心文件。

设备驱动通过 spi_driver 结构体注册到核心层:

static struct spi_driver m25p80_driver = {
    .driver = {
        .name   = "m25p80",
        .of_match_table = m25p_ids,  // 设备树 compatible 匹配表
    },
    .probe  = m25p_probe,
    .remove = m25p_remove,
    .id_table = m25p_ids,
};

module_spi_driver(m25p80_driver);

设备驱动的主要职责:

  • 探测(probe): 读取 Flash ID,识别芯片型号,初始化 MTD 设备。
  • 读写操作: 通过 spi_mem_ops 或直接构造 spi_message 发送 SPI 命令(如 Read、Page Program、Erase)。
  • 分区管理: 解析设备树中的 partitions 节点,注册 MTD 分区。
设备驱动文件 适用场景 关键接口
m25p80.c 通用 SPI NOR Flash(经典框架) m25p80_read() / m25p80_write()
spi-nor.c 现代 SPI NOR Flash 统一框架 spi_nor_read() / spi_nor_write()
spi-mem.c SPI 存储设备抽象层(推荐) spi_mem_exec_op()
适配建议: 在全志 T113 上适配 W25Q128 等 Flash 时,优先使用 spi-nor 框架 + spi-mem 接口。这种方式可以充分利用控制器驱动的 DMA 能力,并且代码维护性更好。

4.5 SPI 设备树绑定

设备树(Device Tree)是 SPI 子系统硬件拓扑的描述语言。全志 T113 的设备树文件通常位于 arch/arm/boot/dts/sun8i-t113*.dts 中。

一个典型的 SPI 控制器节点及其 Flash 子节点如下:

&spi0 {
    status = "okay";
    pinctrl-names = "default";
    pinctrl-0 = <&spi0_pins>;
    cs-gpios = <&pio PC 3 GPIO_ACTIVE_LOW>;  // 片选 GPIO

    flash@0 {
        compatible = "jedec,spi-nor";           // 通用 SPI NOR Flash 匹配
        reg = <0>;                              // 片选索引 0
        spi-max-frequency = <80000000>;         // 最大 SPI 时钟 80MHz
        spi-rx-bus-width = <4>;                // 四线读取(QSPI 模式)
        spi-tx-bus-width = <4>;

        partitions {
            compatible = "fixed-partitions";
            #address-cells = <1>;
            #size-cells = <1>;

            partition@0 {
                label = "boot";
                reg = <0x000000 0x100000>;      // 1MB 启动分区
            };
            partition@1 {
                label = "rootfs";
                reg = <0x100000 0x700000>;      // 7MB 根文件系统
            };
        };
    };
};

设备树绑定的关键属性说明:

属性 说明 典型值
compatible 驱动匹配字符串,核心层据此查找对应的 spi_driver "jedec,spi-nor" 或 "w25q128"
reg 片选编号,从 0 开始 <0>
spi-max-frequency SPI 总线最高时钟频率(Hz) <80000000>
spi-rx-bus-width 接收数据总线宽度(1/2/4 线) <4> 启用 QSPI 四线模式
spi-tx-bus-width 发送数据总线宽度 <4>
cs-gpios 片选 GPIO 控制(在控制器节点中定义) <&pio PC 3 GPIO_ACTIVE_LOW>
设备树绑定与驱动匹配流程 设备树 .dts 文件 内核解析 SPI 子节点 SPI 核心层匹配 compatible 驱动 probe() 创建 spi_device 并注册 说明: 设备树中的 compatible = "jedec,spi-nor" 匹配到 spi-nor 驱动, 驱动 probe 后通过 spi_mem_ops 与控制器驱动交互。
常见错误: 设备树中 spi-max-frequency 设置过高(超过 Flash 芯片或控制器支持上限)会导致通信不稳定或数据错误。全志 T113 的 SPI 控制器最高通常支持 100MHz,但 W25Q128 等 Flash 在四线模式下建议不超过 80MHz。务必参考芯片数据手册确认。

4.6 本章小结

Linux SPI 子系统的分层设计为全志 T113 平台上的 SPI Flash 驱动适配提供了清晰的框架:

  • SPI 核心层 提供总线管理与传输调度,是上下层的桥梁。
  • SPI 控制器驱动层 直接操作 T113 硬件寄存器,实现底层时序。
  • SPI 设备驱动层 实现 Flash 协议,通过 MTD 层向用户空间提供存储接口。
  • 设备树绑定 将硬件拓扑与驱动匹配规则静态描述,实现即插即用。