常见问题
如何添加新的 SPI NAND 设备
- 驱动层次关系SPI NAND 属于 SPI 的从设备,在内核中相关驱动通过
SPI MEM
对接到 SPI 子系统,如内核 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/ - 检查和添加新设备内核中所支持的 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, };
- 检查具体的设备厂商文件,具体的型号是否在列表之中( 以 gigadevice
为例):
static const struct spinand_info gigadevice_spinand_table[] = { SPINAND_INFO("GD5F1GQ4UExxG", SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xd1), NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1), NAND_ECCREQ(8, 512), SPINAND_INFO_OP_VARIANTS(&read_cache_variants, &write_cache_variants, &update_cache_variants), SPINAND_HAS_QE_BIT, SPINAND_ECCINFO(&gd5fxgq4_variant2_ooblayout, gd5fxgq4uexxg_ecc_get_status)), ...... };
此处检查,需要查找新设备的 Datasheet,找到该设备的 Device ID(可在 Datasheet 中直接搜索 “Device ID”)。 并查看该 Device ID 是否出现在列表中。例如此处
SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xd1),
的最后一个数值0xd1
就是 一个 Device ID 值。如果不存在,则参考上述例子,添加一个新的设备记录。
- 检查
- 修改 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"; 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; }; };
- 在实际项目中使用 SPI NAND 设备,还需要修改 DTS 配置。
如何添加新的 SPI NOR 设备
- 驱动层次关系SPI NOR 属于 SPI 的从设备,在内核中相关驱动通过
SPI MEM
对接到 SPI 子系统,如 所示。 在 SPI 控制器初始化时,SPI 驱动会检查该控制器下是否有挂载的 SPI NOR,有则添加到 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 NOR source/linux-5.10/drivers/mtd/spi-nor/ - 检查和添加新设备
内核中所支持的 SPI NOR 设备通过两级列表进行设置。
-
检查
source/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[] = { ...... { "gd25q256", INFO(0xc84019, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_TB_SR_BIT6) .fixups = &gd25q256_fixups }, ...... };
此处检查,需要查找新设备的 Datasheet,找到该设备的 Manufacture 和 Device ID,并查看该 ID 是否出现在列表中。 例如此处为
0xc84019
,其中 Manufacture ID =0xc8
, Device ID ID[15~8] =0x40
, ID[7~0] =0x19
。如果不存在,则参考上述例子,添加一个新的设备记录。
-
- 修改 DTS
要在实际项目中使用 SPI NOR 设备,还需要修改 DTS 配置。
board.dts 应在具体的 SPI 控制器下添加
jedec,spi-nor
设备。&spi0 { pinctrl-names = "default"; pinctrl-0 = <&spi0_pins_a>; status = "okay"; spi-max-frequency = <100000000>; spi-flash@0 { #address-cells = <1>; #size-cells = <1>; compatible = "jedec,spi-nor"; 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 无法识别和使用。&spi0 { u-boot,dm-pre-reloc; spi-flash@0 { u-boot,dm-pre-reloc; }; };