3.8.4. SPI 驱动

SPI 在 U-Boot 中主要用于支持 SPI NAND/NOR 存储设备。目前 ZX 平台上 SPI 的实现只支持半双工模式(Half-duplex)。

3.8.4.1. 驱动框架

U-Boot 驱动模型支持 SPI,ZX 平台中 SPI 驱动基于该框架进行实现。 相关配置为:

  • CONFIG_DM_SPI

  • CONFIG_SPI

  • CONFIG_SPL_SPI_SUPPORT

  • CONFIG_ZX_SPI

相关源码有:

  • drivers/spi/spi-uclass.c

  • include/spi.h

  • drivers/spi/zx_spi.c

3.8.4.2. 驱动接口

常用接口:

int dm_spi_claim_bus(struct udevice *dev);
void dm_spi_release_bus(struct udevice *dev);
int dm_spi_xfer(struct udevice *dev, unsigned int bitlen,
                const void *dout, void *din, unsigned long flags);
int spi_claim_bus(struct spi_slave *slave);
void spi_release_bus(struct spi_slave *slave);
int  spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
              void *din, unsigned long flags);

3.8.4.3. 初始化流程

SPI 设备挂载在 SPI 总线上,当 SPI 设备初始化时,如果父设备还没有被初始化, 则会自动触发父设备的初始化。下面是 SPI NAND 初始化时触发 SPI 初始化的流程。

mtd_probe(dev)
|-> device_probe(dev)
    |   // 此时 SPI 还没有 probe,则先 probe SPI
    |-> device_probe(dev->parent); // drivers/core/device.c
    |   |-> drv->probe(dev);
    |       aic_spi_probe(dev); // drivers/spi/zx_spi.c
    |
    |-> drv->probe(dev);
        spinand_probe(dev) // drivers/mtd/nand/spi/core.c

3.8.4.4. DMA 的支持

ZX SPI 驱动支持使用 DMA 收发数据和使用 FIFO 通过 CPU 读写的方式收发数据, 在 DMA 使能的情况下,对于数据长度大于等于 SPI_FIFO_DEPTH 的传输,驱动自动切换使用 DMA 进行传输,否则默认使用 FIFO 模式。

如果系统没有使能 DMA,则所有传输都使用 FIFO 模式。

使能 DMA 的 Kconfig 配置为:

  • CONFIG_ZX_DMA

3.8.4.5. QUAD SPI 的支持

对于非存储 SPI 设备,SPI 驱动只支持标准 SPI 模式,即 Single Mode,数据传输都使用一根线进行(MOSI 和 MISO)。 对于 SPI 存储设备(SPI NAND/SPI NOR),通过对接 spi-mem 框架,可以支持 DUAL SPI 和 QUAD SPI。

相关代码:

static const struct spi_controller_mem_ops aic_spi_mem_ops = {
    .supports_op = aic_spi_mem_supports_op,
    .exec_op = aic_spi_mem_exec_op,
};
static const struct dm_spi_ops aic_spi_ops = {
    .claim_bus   = aic_spi_claim_bus,
    .release_bus = aic_spi_release_bus,
    .xfer        = aic_spi_xfer,
    .set_speed   = aic_spi_set_speed,
    .set_mode    = aic_spi_set_mode,
    .mem_ops     = &aic_spi_mem_ops,
};

通过设置 .exec_op ,SPI MEM 设备的所有操作都由 aic_spi_mem_exec_op 进行处理。 由于该接口可以获取到 SPI 操作的数据位宽等详细信息,驱动可以为每一个传输操作设置准确的模式(Single/Dual/Quad)。