4. TF-A移植基础
在STM32MP系列(如STM32MP157、STM32MP135)的Linux BSP中,TF-A(Trusted Firmware-A)承担着从ROM Code交出控制权到U-Boot正式接管之间的全部关键工作。理解TF-A的启动阶段划分、各镜像的职责边界,以及平台移植时应该改哪些文件,是BSP移植能否顺利推进的分水岭。很多移植失败并不是U-Boot或内核的问题,而是TF-A阶段DDR未初始化正确、电源域未打开、或BL33入口地址配置错误,导致系统在极早期就静默挂死。
一、STM32MP TF-A的启动阶段划分
STM32MP1的启动链遵循ARM Trusted Firmware的标准分层模型,但ST在此基础上做了平台化封装。上电后,片内ROM Code首先执行,它根据BOOT引脚(BOOT0/BOOT1/BOOT2)选择启动介质,从FSBL(First Stage Boot Loader)分区加载TF-A的BL2镜像到片内SYSRAM(STM32MP157约256KB)中运行。ROM Code只做最基础的加载和鉴权,不初始化DDR。
BL2运行在SYSRAM中,它的核心任务是完成平台早期初始化:时钟树配置、DDR初始化、电源域(PD)与调节器配置、安全外设初始化,然后依次加载并校验后续镜像。BL2之后进入BL32(OP-TEE)和BL33(U-Boot),最终由BL33跳转到Linux内核。整个链条可以概括为:ROM Code → BL2 → BL32 → BL33 → Linux Kernel。
二、BL2的核心职责与移植关注点
BL2是移植工作量最集中的阶段。它运行在SYSRAM中,空间有限,因此代码必须精简。BL2的主要职责包括:
- 时钟初始化:配置PLL1/PLL2/PLL3/PLL4,确定CPU、AXI、DDR、外设时钟频率。STM32MP157的PLL配置在设备树中通过
st,clksrc、st,pll等属性描述,BL2解析后写入RCC寄存器。 - DDR初始化:调用STM32MP DDR驱动,根据DDR类型(DDR3/DDR3L/LPDDR2/LPDDR3)和容量配置时序参数。这是最容易出问题的环节,参数错误会导致BL2加载BL33时数据校验失败。
- 电源域与调节器:使能VDDCORE、VDD_DDR等调节器,打开需要使用的电源域(如PD_DDR、PD_GPU等)。
- 镜像加载与校验:从启动介质读取BL32和BL33镜像,校验签名后放入DDR指定地址。
移植时,BL2阶段最常修改的文件是plat/st/stm32mp1/stm32mp1_def.h(定义DDR基地址、BL32/BL33加载地址)和fdts/stm32mp157*.dts(时钟、DDR、电源域配置)。如果使用自定义板卡,通常从ST官方EVAL或DK板设备树复制一份,修改DDR参数和引脚复用即可。
三、BL32与BL33的职责边界
BL32即OP-TEE,运行在ARM TrustZone的安全世界(Secure World)。它提供安全服务,如安全存储、加密引擎访问、SMC(Secure Monitor Call)处理。在STM32MP1上,BL32通常被加载到DDR的安全区域,由BL2完成加载和跳转。如果项目不需要安全功能,可以裁剪BL32,但ST的默认启动链通常包含它。
BL33即U-Boot,运行在非安全世界(Non-Secure World)。它负责加载Linux内核和设备树,提供命令行交互、网络启动、存储访问等功能。BL2在完成BL32加载后,会将控制权交给BL32,BL32再通过SMC返回非安全世界,最终跳转到BL33入口。BL33的入口地址由BL33_BASE定义,通常位于DDR中,例如STM32MP157上常配置为0xC0100000。
四、平台移植入口与实操示例
以STM32MP157自定义板为例,移植TF-A的典型流程如下:
- 从ST官方仓库获取TF-A源码,切换到与BSP匹配的版本分支(如
v2.6-stm32mp1)。 - 在
fdts/目录下复制stm32mp157d-dk1.dts为stm32mp157d-myboard.dts,修改DDR节点参数(容量、时序)、时钟节点(晶振频率)、pinctrl(UART、SDMMC引脚)。 - 在
plat/st/stm32mp1/platform.mk中确认STM32MP_EMMC、STM32MP_SDMMC等启动介质宏定义与硬件一致。 - 检查
stm32mp1_def.h中的BL33_BASE和BL32_BASE,确保与DDR布局匹配。 - 编译:
make PLAT=stm32mp1 ARCH=aarch32 ARM_ARCH_MAJOR=7 AARCH32_SP=optee DTB_FILE_NAME=stm32mp157d-myboard.dtb。 - 生成FIP包,使用STM32CubeProgrammer烧录到eMMC或SD卡。
编译完成后,可以通过串口观察BL2的启动日志。正常日志会打印DDR初始化结果、时钟频率、镜像加载地址。如果卡在BL2: Loading BL33之后无输出,通常需要检查DDR参数或BL33_BASE地址。如果BL2阶段直接无任何输出,则可能是SYSRAM溢出或时钟配置错误导致BL2无法运行。
五、移植检查清单
| 检查项 | 文件/位置 | 判断依据 |
|---|---|---|
| DDR容量与地址 | 设备树memory节点、stm32mp1_def.h | BL33_BASE + 镜像大小 ≤ DDR末端 |
| 时钟频率 | 设备树clocks节点、RCC寄存器 | 串口波特率正常,DDR时钟在规格内 |
| 启动介质 | platform.mk、BOOT引脚 | 与硬件实际启动方式一致 |
| BL32/BL33入口 | stm32mp1_def.h | 与U-Boot/OP-TEE链接地址一致 |
| 电源域 | 设备树regulators、pd节点 | 所需外设电源已使能 |