4. R-Car启动链与系统初始化
R-Car SoC 上电后的启动过程是一条严格分阶段的信任链:从芯片内部固化的 BootROM 开始,逐级把控制权交给可验证、可替换的软件层,最终进入 Linux 用户空间。理解这条链的每一跳、每一跳的输入输出以及时间开销,是数字仪表与多屏座舱系统能否在 2 秒内点亮屏幕的前提。本节以 R-Car H3/M3 系列为参照对象,梳理 BootROM → TF-A(BL2/BL31)→ U-Boot → Linux 内核 → 根文件系统的完整路径,并给出启动时间测量与串口日志判读的实操方法。
一、启动链的四个阶段与信任传递
R-Car 的启动介质由芯片采样引脚(MD 引脚)在上电复位时决定,常见为 QSPI Flash(SPI NOR)、eMMC 或 SD 卡。BootROM 是固化在 SoC 内部 ROM 中的第一段代码,它只做三件事:初始化最小化的时钟与启动介质控制器、从介质固定偏移读取 Boot 程序、用内嵌的公钥验证其签名。R-Car 采用 BootROM 内置的 HSM(Hardware Security Module)根密钥,验证的是经 RSA 签名的 BL2 镜像头部。验证通过后,BootROM 把 BL2 载入片上 SRAM(R-Car H3 约 1MB 可用),跳转执行。
TF-A(Trusted Firmware-A)在 R-Car 上被拆分为 BL2 与 BL31 两个可加载阶段。BL2 运行于 SRAM,负责初始化 DDR 控制器、完成 DDR 训练、把 BL31、BL33(即 U-Boot)以及可选的 OP-TEE 从 Flash 搬到 DDR 中的目标地址,然后跳入 BL31。BL31 常驻 EL3,提供 PSCI 电源管理、SMC 调用入口,并在系统运行期间一直存在。BL33 就是 U-Boot 的 proper 阶段,运行在 EL2 或 EL1。
U-Boot 承担设备树选择、环境变量加载、内核与 initramfs 搬运、启动参数拼装。R-Car 的 U-Boot 通常从 bootargs 中读取 console=ttySC0,115200 之类的串口配置,并通过 booti 或 bootm 跳转到内核。内核解压、建立页表、初始化驱动,最后挂载根文件系统并执行 /sbin/init,启动链结束。
二、启动时间优化的三个着力点
从上面的时间预算可以看出,DDR 训练、U-Boot 阶段和内核驱动初始化是三个最大的时间块。DDR 训练时间由硬件和训练算法决定,可通过在 BL2 中启用训练结果缓存(DDR 训练数据保存到 Flash,下次启动直接复用)来压缩,但必须确认温度与电压变化下训练结果的稳定性,否则会引入偶发启动失败。U-Boot 阶段可关闭不必要的命令、缩短 bootdelay、使用 booti 直接跳转而不经过脚本解释,并把内核与 DTB 的加载地址对齐到 DDR 的连续区域以减少搬运次数。
内核侧最有效的做法是裁剪配置与并行化。关闭仪表用不到的子系统(如多余的 USB 主机、Wi-Fi、蓝牙、调试文件系统),把驱动编译为模块而非内建,可显著缩短 probe 阶段。对于必须内建的显示与 GPU 驱动,可通过 initcall_debug 观察每个驱动的初始化耗时,定位拖慢启动的驱动。用户空间侧则用 systemd 的 systemd-analyze blame 找出耗时服务,把仪表 HMI 的首帧渲染提前到关键服务就绪之后立即执行,而不是等待所有服务启动完毕。
三、调试串口日志的判读方法
R-Car 的调试串口通常接在 SCIF 或 HSCIF 上,默认 115200-8N1。串口日志是判断启动卡在哪一级的唯一可靠依据。判读时按阶段看关键标志:BootROM 阶段通常只输出极少的字符或完全静默;BL2 会打印 DDR 训练结果与镜像校验信息;BL31 打印 PSCI 初始化;U-Boot 打印版本、DRAM 容量、设备树加载地址;内核打印 Booting Linux on physical CPU 与解压信息。
# 典型串口日志片段(示例,非实测)
NOTICE: BL2: R-Car H3 DDR training done
NOTICE: BL2: Loading BL31 @ 0x40000000
NOTICE: BL31: PSCI init complete
U-Boot 2021.10 (Jan 10 2025 - 10:00:00 +0800)
DRAM: 4 GiB
Loading Device Tree to 0x48000000, end 0x4802ffff ... OK
Starting kernel ...
[ 0.000000] Booting Linux on physical CPU 0x0000000000
[ 0.352100] rcar-drm fec00000.display: bound
[ 1.204500] systemd[1]: Reached target Multi-User System.
如果日志停在 Starting kernel ... 之后没有任何输出,常见原因是内核镜像加载地址与 DDR 保留区冲突、串口控制台参数不匹配,或 DTB 中 chosen 节点的 stdout-path 指向了错误的串口。如果日志停在 BL2 的 DDR 训练阶段,则应检查 DDR 颗粒型号与训练参数是否匹配,以及供电是否稳定。若日志能进入 U-Boot 但无法加载内核,优先核对 bootargs 中的 root= 与 console= 是否与实际根文件系统位置一致。
四、可复用的启动检查清单
| 阶段 | 检查项 | 判断依据 |
|---|---|---|
| BootROM | MD 引脚电平、启动介质焊接 | 上电后串口是否有 BL2 校验输出 |
| BL2 | DDR 训练参数、供电纹波 | 日志出现 DDR training done |
| BL31 | PSCI 初始化、SMC 入口 | 日志出现 PSCI init complete |
| U-Boot | bootargs、加载地址、DTB | Starting kernel 前无报错 |
| 内核 | console 参数、rootfs 挂载 | 出现 systemd 或 init 启动日志 |
| 用户空间 | HMI 服务依赖、首帧渲染 | 屏幕点亮且仪表画面出现 |
把这条链上的每一跳都当作可独立验证的环节,配合串口日志与时间戳,就能在出现启动失败或超时时快速定位到具体阶段,而不是在整条链上盲目试错。对于数字仪表项目,建议在样机阶段就固化一份带时间戳的启动日志基线,后续每次修改 BL2、U-Boot 或内核配置后与基线对比,任何超过 50ms 的偏差都值得追查。