2. R-Car硬件启动链路解析

R-Car座舱SoC的启动并不是“上电即跑Linux”这么简单。在Linux内核获得控制权之前,芯片内部已经历了一条由硬件状态机、固化代码和分阶段引导程序共同构成的链路。理解这条链路的阶段划分、每段代码的职责边界,以及在哪里插入耗时测量点,是后续做启动优化的前提。本节以R-Car H3/M3这类典型座舱SoC为对象,梳理从PMIC上电到U-Boot移交内核的完整过程。

一、启动阶段的整体划分

R-Car的启动链路可以划分为五个逻辑阶段。第一阶段是PMIC上电与电源域建立,此时SoC尚未执行任何指令,由外部PMIC按上电时序依次输出各路电源。第二阶段是BootROM执行,芯片内部的固化代码从启动介质(eMMC、QSPI Flash或SD)读取第一阶段引导程序。第三阶段是TF-A/BL31运行,完成可信固件初始化、DDR训练与安全启动校验。第四阶段是U-Boot运行,负责加载内核、设备树与根文件系统。第五阶段是内核启动,已超出本节范围。

需要特别注意的是,R-Car的BL31(TF-A)与U-Boot之间存在明确的交接关系。BL31在完成DDR初始化和安全环境搭建后,将控制权交给BL33(即U-Boot)。因此,测量点必须覆盖“BL31结束”与“U-Boot开始”之间的边界,否则容易把DDR训练耗时误算到U-Boot阶段。

R-Car 启动链路阶段划分与耗时测量点 ① PMIC 上电 VDD_CORE / VDD_DDR VDD_IO / VDD_1V8 PWRON → RESET 释放 ② BootROM MD 引脚采样 读取 BL2 到 SRAM 校验头部与签名 ③ TF-A / BL31 DDR 训练与初始化 安全环境 / 异常向量 加载 BL33 到 DRAM ④ U-Boot 驱动初始化 加载 Image / DTB bootargs 传递 ⑤ Kernel 解压 / 初始化 挂载 rootfs init 进程 关键耗时测量点(GPIO 翻转 / 时间戳) M1: PWRON 拉高 PMIC 输出稳定 M2: RESET 释放 BootROM 首条指令 M3: BL2 入口 TF-A 开始执行 M4: BL31 退出 U-Boot 入口 M5: bootm 调用 内核入口 各阶段关键寄存器 / 状态观察点 PMIC 阶段 PWRON 电平 RESET# 释放沿 各路电源 PG 信号 BootROM 阶段 MD[3:0] 采样值 启动介质选择 BL2 头部校验结果 TF-A / BL31 阶段 DDR 训练寄存器 DBSC / DDRPHY 状态 安全启动校验标志 U-Boot 阶段 gd->ram_size bootargs 内容 Image / DTB 加载地址 内核 earlycon initcall rootfs 挂载

二、各阶段职责与关键寄存器状态

PMIC上电阶段。按下PWRON后,PMIC按预设时序依次建立VDD_CORE、VDD_DDR、VDD_IO等电源域。此时SoC的RESET#引脚仍被拉低,CPU不执行指令。判断电源是否就绪,可观察PMIC的Power Good(PG)信号是否全部拉高,以及RESET#是否在最后一个电源域稳定后释放。这一段的耗时通常由PMIC数据手册中的上电时序决定,典型值在几毫秒到十几毫秒之间。

BootROM阶段。RESET#释放后,CPU从固化在芯片内部的BootROM开始执行。BootROM首先采样MD[3:0]引脚,确定启动介质(例如MD=0b0001对应QSPI,0b0010对应eMMC)。随后从所选介质读取BL2镜像到内部SRAM,并校验镜像头部与签名。若校验失败,BootROM会尝试下一个启动介质或进入恢复模式。这一阶段的关键观察点是MD引脚采样值和BL2头部校验结果,耗时通常在几毫秒量级,但受启动介质读取速度影响。

TF-A/BL31阶段。BL2将BL31加载到DRAM后跳转执行。BL31的核心任务是DDR训练与初始化、建立安全环境(如设置异常向量、配置TrustZone)、以及将BL33(U-Boot)加载到DRAM。DDR训练是这一阶段最耗时的部分,涉及DDRPHY的写电平、读门控、地址线训练等。可通过读取DBSC和DDRPHY相关寄存器确认训练是否完成。若DDR训练失败,BL31通常会通过串口输出错误码并停止。

U-Boot阶段。BL31将控制权交给U-Boot后,U-Boot完成串口、存储、网络等驱动初始化,然后从存储介质加载内核Image和设备树DTB到DRAM,设置bootargs,最后调用bootm跳转到内核入口。这一阶段的关键观察点是gd->ram_size是否正确、bootargs是否包含正确的console和root参数、以及Image/DTB的加载地址是否与内核约定一致。

三、耗时测量点的插入方法

要量化各阶段耗时,最直接的方法是在关键边界翻转GPIO,用示波器或逻辑分析仪记录时间差。例如,在PMIC的PWRON信号上接一路探头,在SoC的RESET#上接一路,即可测出“PWRON到RESET释放”的电源建立时间。在BL2入口和BL31退出点各翻转一个GPIO,可测出BootROM与TF-A的耗时。

若不具备GPIO翻转条件,也可利用串口时间戳。在U-Boot中开启CONFIG_BOOTSTAGE,内核侧开启bootgraph或initcall_debug,可以分别获得U-Boot阶段和内核阶段的耗时分布。但要注意,串口输出本身会引入额外延迟,测量时应尽量使用高波特率并减少打印量。

测量点选择建议:优先在阶段边界插入测量点,而不是在阶段内部。阶段内部的耗时往往由具体驱动或训练算法决定,边界测量才能清晰划分责任归属。例如,DDR训练耗时应归属BL31,而不是U-Boot。

四、常见异常与判断依据

如果启动在BootROM阶段停止,通常表现为串口无任何输出。此时应检查MD引脚电平是否正确、启动介质是否可读、BL2镜像头部是否合法。如果启动在BL31阶段停止,串口可能输出DDR训练失败的错误码,应检查DDR颗粒型号与训练参数是否匹配。如果启动在U-Boot阶段停止,通常能看到U-Boot的启动日志,可根据日志最后一行判断是驱动初始化失败还是内核加载失败。

掌握这条链路的阶段划分与测量点,后续做启动优化时就能准确定位瓶颈。例如,若测量发现BL31阶段耗时占比过高,优化方向应集中在DDR训练参数和BL31镜像裁剪上,而不是盲目裁剪U-Boot。