SPI NAND 使用指南
1. 配置指南
1.1. 驱动层次关系
SPI NAND 属于 SPI 的从设备,在内核中相关驱动通过 SPI MEM
对接到 SPI 子系统。 在 SPI 控制器初始化时,SPI 驱动会检查该控制器下是否有挂载的 SPI NAND,有则添加到 SPI BUS 中。
aic_spi_probe(dev);
|-> spi_register_controller(ctlr);/spi_register_master(ctlr);/ spi_register_master 是一个宏
|-> of_register_spi_devices(ctlr);
|-> spi = of_register_spi_device(ctlr, nc);
|-> spi = spi_alloc_device(ctlr);
|-> of_spi_parse_dt(ctlr, spi, nc);
|-> rc = spi_add_device(spi);
// 将 SPI device 添加到 SPI 总线 spi_bus_type 中
在调用 spi_add_device
的过程中,会查找和匹配对应设备的驱动程序(如果这时候对 应的驱动程序还没有被添加到系统中,则在这里先将设备添加到 Bus,等到对应驱动程序 被添加进来时,再进行匹配。)
模块 | 驱动源码路径 |
---|---|
SPI NAND | source/linux-5.10/drivers/mtd/nand/spi/ |
1.2. 修改 DTS
要在实际项目中使用 SPI NAND 设备,还需要修改 DTS 配置。
board.dts
应在具体的 SPI 控制器下添加 spi-nand
设备。
&spi1 {
pinctrl-names = "default";
pinctrl-0 = <&spi1_pins_a>;
status = "okay";
spi-max-frequency = <100000000>;
spi-flash@0 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "spi-nand"; // 固定值,所有 SPINand 驱动均声明此
spi-max-frequency = <100000000>; //最大频率,固定值
spi-tx-bus-width = <4>;
spi-rx-bus-width = <4>;
reg = <0>; //固定值,一般不需修改
status = "okay";
};
};
同时还需在 board-u-boot.dtsi
文件中,将该设备标记为 u-boot,dm-pre-reloc
,不然 SPL 无法识别和使用。
&spi1 {
u-boot,dm-pre-reloc;
spi-flash@0 {
u-boot,dm-pre-reloc;
};
};
1.3. Bus Width
宽总线的 SPI NAND 芯片可以工作在窄总线下,如4线的 SPI NAND 配置为1线也可以工作,但读写速度损失, 但窄总线设备无法工作在宽总线模式下,因此 spi-tx-bus-width 要正确设置
- 标准 SPI NAND 配置为1
- Dual SPI NAND 配置为2
- Quad SPI NAND 配置为4
2. 移植指南
SPI NAND 要工作既需要 SOC 端 SPI 模块的驱动能力,也需要对 SPI NAND 模块的正确配置,本章阐述如何进行 SPI NAND 器件的移植工作,以 FudanMicro
的 FM25S01A
和 Foresee
的 F35SQA002G
为例
注解
SPI NAND 在 U-Boot 和 Kernel 中的实现逻辑类似,文件路径和内容基本一致,本文以 Kernel 中的移植为例
2.1. 文件准备
一般情况下,某一个公司的 SPI NAND 的操作接口是类似,因此会为某一个公司创建一个文件进行管理,如果该公司的文件已经存在,则直接添加新器件支持即可
- 在source/linux-5.10/drivers/mtd/nand/spi 下建相应公司的标识的文件,如 fmsh.c foresee.c
- 在Makefile中添加该文件的编译 spinand-objs := core.o fmsh.o foresee.o …
- 在include/linux/mtd/spinand.h 中声明 extern const struct spinand_manufacturer fmsh_spinand_manufacturer;
2.2. 驱动索引
不同于传统驱动通过 board.dts 进行设备和驱动的关联,内核中所支持的 SPI NAND 设备和驱动的关联关系通过两级列表进行设置。
- 首先检查 source/linux-5.10/drivers/mtd/nand/spi/core.c 中的 spinand_manufacturers, 查看新设备的厂商是否在列表之中:
static const struct spinand_manufacturer *spinand_manufacturers[] = {
&gigadevice_spinand_manufacturer,
¯onix_spinand_manufacturer,
µn_spinand_manufacturer,
¶gon_spinand_manufacturer,
&toshiba_spinand_manufacturer,
&winbond_spinand_manufacturer,
&fmsh_spinand_manufacturer,
&foresee_spinand_manufacturer,
};
- 再检查具体的设备厂商文件,具体的型号是否在列表之中( 以 FudanMicro 为例):
static const struct spinand_info fmsh_spinand_table[] = {
SPINAND_INFO("FM25S01A",
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xE4),
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(1, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&fm25s01_ooblayout,
fm25s01_ecc_get_status)),
};