Edit online

常见问题

3 Dec 2024
Read time: 4 minute(s)

如何添加新的 SPI NAND 设备

  1. 驱动层次关系
    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/
  2. 检查和添加新设备
    内核中所支持的 SPI NAND 设备通过两级列表进行设置。
    1. 检查 source/linux-5.10/drivers/mtd/nand/spi/core.c 中的 spinand_manufacturers, 查看新设备的厂商是否在列表之中:
      static const struct spinand_manufacturer *spinand_manufacturers[] = {
          &gigadevice_spinand_manufacturer,
          &macronix_spinand_manufacturer,
          &micron_spinand_manufacturer,
          &paragon_spinand_manufacturer,
          &toshiba_spinand_manufacturer,
          &winbond_spinand_manufacturer,
      };
    2. 检查具体的设备厂商文件,具体的型号是否在列表之中( 以 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 值。

      如果不存在,则参考上述例子,添加一个新的设备记录。

  3. 修改 DTS
    1. 在实际项目中使用 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";
          };
      };
      
    2. 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 NOR 设备

  1. 驱动层次关系
    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/
  2. 检查和添加新设备

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

    1. 检查 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,
      };
    2. 检查具体的设备厂商文件,具体的型号是否在列表之中( 以 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

      如果不存在,则参考上述例子,添加一个新的设备记录。

  3. 修改 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;
        };
    };