BootROM 中 SPI 如何适配不同厂家的 Flash 芯片

问题背景

一款 SoC 芯片,会支持多种方式启动,比如从 NAND Flash、SPI Flash、eMMC、USB、UART 启动。对于 SPI Flash 启动,BootROM 需要知道 SPI Flash 的型号、容量、页大小、擦除大小等信息,以便正确读取、写入、擦除 SPI Flash。但是,不同厂家的 SPI Flash,这些参数可能不同,而 ROM 中的代码是无法修改的,并且容量有限,如何以最小的代码量,适配不同厂家的 SPI Flash 呢?

SPI 开发流程

  • SPI 控制器初始

    • SPI 控制器有自己的寄存器,可以配置 SPI 的页,块的擦除时间,是否需要 DMA,是否开启中断,单次读写的大小等等。
  • 使用 SPI 对 Flash 进行配置

    • BootROM 的 SPI 支持三种模式:Single、Dual、Quad,这不仅要配置 SPI 本身的寄存器,也需要配置 Flash 的寄存器。配置 Flash 的寄存器就需要使用 SPI 来完成。
      • BootROM 中配置 SPI 控制器的 SPIC_CSR_01 寄存器的spi_bus_mode 位可以配置 SPI 的模式;
      • 查阅 Flash 手册,找到配置总线模式的寄存器以及操作它的命令,如 WINBOND-W25Q128JW 这款 Flash 的配置寄存器为 Status Register-2,Flash 的寄存器是无法直接读写的,所以需要在 Flash 手册中找到操作这个寄存器的命令,在手册的 Instructions 章节可以找到这款 Flash 的配置命令为 Write Status Register-2,命令码为 0x31,只要我们向 Flash 发送 0x31,就可以配置 Flash 的总线模式了。

      • 如何向 Flash 发送指令?需要将真正要发送的指令写入 SPI 的寄存器SPIC_CSR_06,该寄存器的各个 Bit 可以配置命令码,命令类型,命令是否有效等信息。我们将之前的命令码0x31写入到SPIC_CSR_06command_code位,然后将SPIC_CSR_06command_type位设置为write status register,SPI 就会自动将这些信息发送给 Flash。Flash 接收到命令后,会根据命令码执行配置寄存器的操作。
  • SPI 读写 Flash

    • 和配置 Flash 总线模式一样,读写 Flash 也需要配置 SPI 控制器的寄存器,以及配置 Flash 的寄存器。SPI 控制器的寄存器配置和配置 Flash 总线模式一样,只是命令码和命令类型不同。稍有不同的是需要先配置好 SPI 寄存器,配置读写的大小以及读写的地址,然后再配置SPIC_CSR_06。Flash接收到命令后,会根据命令码执行读写操作。主设备只需要读写 Flash 的指定地址即可读写到数据。

SPI 驱动如何适配不同的 Flash

在开发流程中我们并未考虑不同厂家的 Flash 如何操作,只是关心了 WINBOND-W25Q128JW 这款 Flash 的操作。在操作过程中我们可以发现,不同厂家的 Flash 的操作基本一致,只是命令码、页大小、擦除大小等参数不同。我们只要针对不同的 Flash,配置不同的参数即可。但是,如何知道当前 Flash 的参数呢?这就需要用到 SFDP 了。

SFDP 是 JEDEC 发布的 JESD216 的一个新标准,目前的版本号是 V1.0。简而言之,SFDP(Serial Flash Discoverable Parameters)就相当于一张存储了 FLASH 部分属性的表,此表是不占用 FLASH 本身的存储空间的。SFDP 中的信息自出厂就被固定,只供读取,开发人员可通过发送操作指令 0x5A 来读取当前 FLASH 的 SFDP 相关内容,这有利于开发人员了解 FLASH 之间的差异,提高开发效率,缩短整个开发周期。

也就是只要 Flash 研发时遵循了 JESD216 这个标准,我们都可以通过发送 0x5A 这个命令码,去获取Flash相关参数。最为关键的就是其中会保存 Flash 厂商的 ID,当我们获取到 Flash 厂商的 ID 时,我们就可以根据 ID 执行不同的配置操作。

对于 WINBOND-W25Q128JW 这款 Flash,在数据手册的Feature里就可以看到它是支持 SFDP 的: