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。

STM32MP1 TF-A 启动链与镜像职责 ROM Code 片内固化 加载FSBL到SYSRAM BL2 (FSBL) 时钟树 / DDR初始化 电源域 / 调节器 加载并校验BL32/BL33 BL32 (OP-TEE) 安全世界运行 SMC调用处理 安全服务 BL33 (U-Boot) 非安全世界 加载内核/设备树 启动Linux 平台移植入口(以STM32MP157为例) plat/st/stm32mp1/ stm32mp1_def.h platform.mk bl2_plat_setup.c stm32mp1_private.c 设备树与DDR fdts/stm32mp157*.dts DDR寄存器参数 电源域/时钟节点 pinctrl配置 BL32/BL33入口 BL32_BASE地址 BL33_BASE地址 OP-TEE编译配置 U-Boot入口跳转 编译与烧录 FIP打包 STM32CubeProgrammer 分区表.tsv 签名与鉴权

二、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。

BL32和BL33的加载地址必须与DDR实际可用范围一致。如果DDR容量为512MB,起始地址0xC0000000,则BL33_BASE不能超过0xC0000000+512MB。地址冲突会导致镜像覆盖或跳转异常。

四、平台移植入口与实操示例

以STM32MP157自定义板为例,移植TF-A的典型流程如下:

  1. 从ST官方仓库获取TF-A源码,切换到与BSP匹配的版本分支(如v2.6-stm32mp1)。
  2. 在fdts/目录下复制stm32mp157d-dk1.dts为stm32mp157d-myboard.dts,修改DDR节点参数(容量、时序)、时钟节点(晶振频率)、pinctrl(UART、SDMMC引脚)。
  3. 在plat/st/stm32mp1/platform.mk中确认STM32MP_EMMC、STM32MP_SDMMC等启动介质宏定义与硬件一致。
  4. 检查stm32mp1_def.h中的BL33_BASE和BL32_BASE,确保与DDR布局匹配。
  5. 编译:make PLAT=stm32mp1 ARCH=aarch32 ARM_ARCH_MAJOR=7 AARCH32_SP=optee DTB_FILE_NAME=stm32mp157d-myboard.dtb。
  6. 生成FIP包,使用STM32CubeProgrammer烧录到eMMC或SD卡。

编译完成后,可以通过串口观察BL2的启动日志。正常日志会打印DDR初始化结果、时钟频率、镜像加载地址。如果卡在BL2: Loading BL33之后无输出,通常需要检查DDR参数或BL33_BASE地址。如果BL2阶段直接无任何输出,则可能是SYSRAM溢出或时钟配置错误导致BL2无法运行。

修改DDR参数时,务必参考DDR芯片手册和ST提供的DDR验证工具(STM32MP_DDR_Test)先做参数校准。直接套用其他板卡的DDR时序参数,即使容量相同,也可能因PCB走线差异导致数据眼图不满足要求,表现为启动偶发失败或高温下不稳定。

五、移植检查清单

检查项 文件/位置 判断依据
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节点 所需外设电源已使能