| |||
在 SoC(System on Chip)系统中,从上电复位开始,从外挂的 SPIFlash 加载 Boot 的过程是一个高度硬件固件协作的精妙流程。SPI Master(通常是 SoC 内部集成的 SPI 控制器)在这个过程中扮演着至关重要的角色。
整体 Boot 过程概要:
SoC 上电复位:
电源稳定后,SoC 内部的复位电路释放 cpu 核心和主要子系统。
关键: CPU 核心被设计为在复位结束后,自动从其复位向量地址开始取指执行。这个地址被硬连线(Hardwired) 映射到 SoC 内部的一个特定只读存储器(Boot ROM) 区域。
Boot ROM 代码执行 (第一阶段 Bootloader - BL1):
最小硬件初始化: 配置最基本的时钟源(如内部 RC 振荡器),初始化执行自身代码所需的极小内存区域(可能用片上 SRAM 或 Cache),初始化关键的通信接口 - SPI Master控制器。
确定启动源: 根据 SoC 的设计(如特定 Boot Pin 的电平状态、eFuse 设置或内部寄存器默认值),确定从哪个外部设备加载下一阶段代码。本例中确定为“外挂 SPI Flash”。
SPI Flash引导: 使用刚初始化好的 SPI Master 控制器,按照特定的协议和参数(时钟速度、模式等),从 SPI Flash 的预定地址(通常是最开头,如 0x00000000
)读取一段固定大小的程序代码。这段代码就是下一阶段的 Bootloader(称为 Bootloader Stage 2, BL2 或 SPL/U-Boot SPL/FSBL 等)。读取的大小是预定义的(可能几百字节到几十KB)。
数据校验(可选但推荐): ROM 代码可能对读取到的 BL2 代码进行简单的校验,如长度验证或校验和(Checksum)验证。更高级的安全 SoC 会进行密码学签名验证。
跳转执行: 如果校验通过,CPU 会将控制权跳转到刚加载到内存(通常是 SRAM)中的 BL2 代码入口点。
CPU 开始执行固化在 SoC 内部 Boot ROM 中的代码。这段代码是芯片制造商预先烧录好的,无法修改。
ROM 代码的核心任务:
第二阶段 Bootloader 执行 (BL2):
更深入的硬件初始化: 初始化主时钟(PLLs)、初始化更复杂的硬件模块(如 DDR 内存控制器、更完整的外设、电源管理)、配置引脚复用(Pinmux)。通常会重新配置或优化 SPI Master 设置(例如提高到更快的时钟速率)。
加载完整 Bootloader (BL3) 或内核: 再次使用 SPI Master 控制器,从 SPI Flash 的另一个预定地址读取更大的数据块。这可能是完整的第三阶段 Bootloader(如 U-Boot)、或经过压缩的 Linux 内核映像 (Image/zImage/uImage)
与初始 RAM 文件系统(initramfs/initrd)
,或者是一个完整的固件镜像(Firmware Package)。
数据校验/解压(可选): 对加载的数据进行完整性校验(CRC, SHA, 签名验证)。如果数据是压缩的(如 gzip, LZMA),则执行解压操作。
环境准备: 为即将运行的 OS 内核或应用程序准备运行时环境(例如设置栈指针、设置页表/MMU、传递设备树(DTB)
或 ACPI 信息)。
跳转执行: 将控制权移交给加载到 DDR 内存中的 OS 内核入口点(如果加载的是内核),或者是交给第三阶段 Bootloader (如 U-Boot) 继续执行。
CPU 开始执行从 SPI Flash 加载到内存中的第二阶段 Bootloader(例如 U-Boot SPL, Xilinx FSBL, Rockchip TPL/SPL, TI SYSFW 等)。
BL2 的核心任务:
后续阶段 (BL3 / OS):
第三阶段 Bootloader (如 U-Boot):负责更复杂的引导配置、命令行交互、网络启动加载、最终加载并启动内核。
操作系统内核:初始化自身数据结构、驱动所有硬件、挂载根文件系统、启动用户空间程序。
Boot 期间 SPI Master 需要做什么操作:
在整个 Boot 过程中,SoC 内部的 SPI Master 控制器是访问外挂 SPI Flash 的唯一硬件接口。它需要完成以下关键操作:
初始化和配置 (由 Boot ROM 和 BL2 执行):
设置时钟频率: Boot ROM 代码在初始化 SPI Master 时,会将其配置为一个较低的、可靠的安全时钟速度(例如几 MHz 到十几 MHz)。因为此时主 PLLs 可能还未初始化,只能用基础时钟源,且低速保证在电压/温度波动下能稳定操作。BL2 在初始化完主 PLLs 后,通常会重新配置 SPI Master 到更高的时钟速度(可能几十 MHz 甚至上百 MHz 如果 SoC 和 Flash 支持)以提高加载速度。
设置 SPI 模式: 配置 SPI 时钟极性 (CPOL)
和相位 (CPHA)
模式(如 Mode 0 (CPOL=0, CPHA=0)
或 Mode 3 (CPOL=1, CPHA=1)
)。这必须与外挂 SPI Flash 芯片支持的型号一致(见 Flash 数据手册)。Boot ROM 和 BL2 使用的模式必须相同或者 Boot ROM 读取的模式参数能被 BL2 理解。
设置传输格式: 配置数据位宽(通常是 1-bit, 但现代 SoC 和 Flash 可能支持 4-bit (QSPI)
或 8-bit (Octal SPI)
模式以提高速度)、字节序 (Endianness)
。
配置片选信号 (CS/SSn)
: 控制连接到目标 SPI Flash 的片选信号线。
启用控制器: 激活 SPI Master 控制器。
通信协议操作 (执行 Flash 读取命令):
启动传输:拉低对应的 CSn
信号。
发送指令:串行输出指令字节 (0x03)
。
发送地址:串行输出要读取数据的起始内存地址 (24-bit 或 32-bit, 通常从 0x000000 开始)
。
有些指令 (如 Fast Read 0x0B)
在地址后还需要一个额外的Dummy Cycle 字节(通常为 0x00
或 0xFF
)。
发出读取指令: SPI Master 需要严格按照 SPI Flash 芯片规定的协议向它发送“读取数据”的指令 (Command)
。最基础的指令是Standard Read (0x03)
。
读取数据: SPI Master 在发送完指令、地址、Dummy Cycle(如果需要)后,开始生成时钟信号,并通过 MISO
线串行地读取 SPI Flash 返回的数据字节。它会持续读取,直到达到预设的读取长度(BL2 代码长度或者后续镜像的大小)或者 BL2 主动停止传输。
结束传输: 拉高 CSn
信号。
数据传输到内存 (DMA 或 CPU 协助):
读取到的数据字节需要被存储到 SoC 内部的存储器中供 CPU 执行。
方式一 (DMA): Boot ROM 或 BL2 可能配置 SPI Master 的 DMA 引擎(如果支持),直接将接收到的数据通过总线传输到目标内存地址 (SRAM/DDR)
。这是最高效的方式,减少 CPU 干预。
方式二 (CPU PIO): Boot ROM 代码可能较为简单,采用 **CPU Polling I/O (Programmed I/O)
** 模式。CPU 不断轮询 SPI Master 的状态寄存器,每当数据就绪寄存器指示一个新字节到达时,CPU 读取该字节并将其存入内存。这种方式效率较低,但实现简单。BL2 通常更倾向于使用 DMA。
关键点总结:
Boot ROM 是基石: 它实现了从零开始最基础的硬件初始化和第一跳。它决定了启动源并负责加载 BL2。
SPI Master 是桥梁: 它是 SoC 与外挂 Boot Device (SPI Flash) 通信的唯一硬件通道。
两次关键 SPI 读取:
BL1 (ROM) 使用低速 SPI: 读取小尺寸的 BL2 到 SRAM。
BL2 使用高速 SPI: 读取大尺寸的 BL3/内核到 DDR。
SPI Master 的操作核心:
初始化配置 (Clock, Mode, CS)
。
发送特定的读取指令序列 (Cmd+Addr)
。
高效读取数据流(DMA 优先)。
安全是趋势: 现代 SoC 的 Boot ROM 在加载 BL2 前会进行签名验证,确保其完整性和来源可信。
这个过程确保了即使系统最初的存储器中只有不可编程的 ROM,也能可靠地将存储在外部 SPI Flash 中的复杂启动代码和操作系统加载并运行起来。