5.3.3. Linux 移植

SPI NOR 驱动 Linux 和 U-Boot 的驱动不一样,Linux 中驱动更复杂一些,本章阐述如何在 Linux 中进行 SPI NOR 器件的移植工作,以 Gigadevicegd25q128FudanMicroFM25Q128 为例

5.3.3.1. 文件准备

相较于 SPI NAND 器件, SPI NOR 的接口更加标准,但为了统一管理的方便,还是会为某一个公司创建一个文件进行管理,如果该公司的文件已经存在,则直接添加新器件支持即可

  • 在linux-5.10/drivers/mtd/spi-nor/ 下建相应公司的标识的文件,如 fmsh.c cfx.c

  • 在Makefile中添加该文件的编译: spi-nor-objs += fmsh.o

  • 在linux-5.10/drivers/mtd/spi-nor/core.h 中声明 extern const struct spi_nor_manufacturer spi_nor_fmsh;

5.3.3.2. 驱动索引

内核中所支持的 SPI NOR 设备通过两级列表进行设置。

首先检查 linux-5.10/drivers/mtd/spi-nor/core.c 中的 manufacturers, 查看新设备的厂商是否在列表之中:

static const struct spi_nor_manufacturer *manufacturers[] = {
    &spi_nor_atmel,
    &spi_nor_catalyst,
    &spi_nor_eon,
    &spi_nor_esmt,
    &spi_nor_everspin,
    &spi_nor_fujitsu,
    &spi_nor_gigadevice,
    &spi_nor_intel,
    &spi_nor_issi,
    &spi_nor_macronix,
    &spi_nor_micron,
    &spi_nor_st,
    &spi_nor_spansion,
    &spi_nor_sst,
    &spi_nor_winbond,
    &spi_nor_xilinx,
    &spi_nor_xmc,
    &spi_nor_boya,
};

再检查具体的设备厂商文件,具体的型号是否在列表之中( 以gigadevice 为例):

static const struct flash_info gigadevice_parts[] = {
    ......
   { "gd25q128", INFO(0xc84018, 0, 64 * 1024, 256,
                       SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
                       SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) },
    ......
};

此处检查,需要查找新设备的 Datasheet,找到该设备的 Manufacture 和 Device ID,并查看该 ID 是否出现在列表中。 例如此处为 0xc84018 ,其中 Manufacture ID = 0xc8, Device ID ID[15~8] = 0x40, Device ID[7~0] = 0x18

5.3.3.3. spi_nor_manufacturer

该结构为第一级索引,用来描述器件厂家的信息

SPI NOR 的接口和操作命令很统一,基本没有需要特殊处理的命令

const struct spi_nor_manufacturer spi_nor_fmsh = {
    .name = "FudanMicro",                   //厂家名字标识
    .parts = fmsh_parts,                    //本驱动支持的器件
    .nparts = ARRAY_SIZE(fmsh_parts),       //支持的器件的个数
};

5.3.3.4. flash_info

虽然和 U-Boot 的代码结构不同,但 flash_info 的描述基本类似,详细信息参考 U-Boot 的章节: flash_info

5.3.3.5. id_table

除了使用 dts 的 .compatible = “jedec,spi-nor” 统一匹配所有的 SPI NOR 外,驱动还兼容使用非标准 dts 的使用方式, 即直接在 dts 文件中描述要使用的 SPI NOR 的型号, 但这会造成固件和器件的紧耦合,不推荐使用

static struct spi_mem_driver spi_nor_driver = {
    .spidrv = {
            .driver = {
                    .name = "spi-nor",
                    .of_match_table = spi_nor_of_table,
            },
            .id_table = spi_nor_dev_ids,
    },

static const struct spi_device_id spi_nor_dev_ids[] = {

    /*
     * Entries not used in DTs that should be safe to drop after replacing
     * them with "spi-nor" in platform data.
     */
    {"s25sl064a"},  {"w25x16"},     {"m25p10"},     {"m25px64"},

    /*
     * Entries that were used in DTs without "jedec,spi-nor" fallback and
     * should be kept for backward compatibility.
     */
    {"at25df321a"}, {"at25df641"},  {"at26df081a"},
    {"mx25l4005a"}, {"mx25l1606e"}, {"mx25l6405d"}, {"mx25l12805d"},
    {"mx25l25635e"},{"mx66l51235l"},
    {"n25q064"},    {"n25q128a11"}, {"n25q128a13"}, {"n25q512a"},
    {"s25fl256s1"}, {"s25fl512s"},  {"s25sl12801"}, {"s25fl008k"},
    {"s25fl064k"},

5.3.3.6. 总结

  • 移植一款 SPI NOR,最重要的是 JEDEC ID,通过在数据手册中查找 0x9F 命令获得

  • 其他的参数都可以默认设置,INFO(0xa14017, 0, 64 * 1024, n_sectors, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)

  • 推荐使用标准 dts 进行 SPI NOR 的兼容