2、R-Car启动流程与Bootloader:启动模式、IPL/SPL、ATF、U-Boot移植与配置

做嵌入式开发,尤其是车规级SoC,第一关就是搞懂芯片怎么「醒过来」的。R-Car的启动流程,说实话,比普通MCU复杂不少。它不是一个简单的Bootloader,而是一套多级引导链。我刚开始接触R-Car时,也被这堆缩写搞得头大——IPL、SPL、ATF、U-Boot……今天咱们就把这条链子从头捋一遍。

2.1 启动模式与硬件决定

R-Car上电后,首先看的是硬件管脚电平。这些管脚组合决定了芯片从哪儿加载第一段代码。

启动模式 典型场景 我碰到的坑
HyperFlash / QSPI 量产板,稳定可靠 曾经把QSPI时钟配快了,死活起不来
eMMC / SD卡 开发调试阶段 分区表写错,IPL找不到SPL
串行Flash (RPC) 低成本方案 引脚复用冲突,RPC没初始化成功
USB / 以太网 工厂烧录或紧急恢复 很少用,但关键时刻能救命
注意: 启动管脚一般在硬件设计阶段就固定了。软件改不了,只能适配。我见过一块板子因为电阻焊错,导致启动模式不对,查了两天才发现。

2.2 多级引导链:从IPL到U-Boot

R-Car的引导链,说白了就是「小马拉大车」。芯片内部SRAM很小,装不下完整的Bootloader,所以必须分阶段加载。

  1. IPL (Initial Program Loader) —— 芯片固化的ROM代码,只做一件事:从启动介质里把SPL读到内部SRAM。
  2. SPL (Secondary Program Loader) —— 初始化DDR、时钟、电源管理芯片(PMIC),然后把ATF和U-Boot加载到DDR里。
  3. ATF (ARM Trusted Firmware) —— 负责安全启动、PSCI(电源管理)、异常等级切换。跑在EL3。
  4. U-Boot —— 真正的Bootloader,加载内核、设备树、ramdisk。跑在EL2。

你想想看,这个流程就像接力赛。每一棒只干自己该干的事,干完就交棒。

R-Car 多级引导链流程图 IPL (ROM) 初始化最小外设 SPL 初始化DDR/时钟 ATF (BL2/BL31) 安全启动 / PSCI U-Boot 加载内核 / DTB 存储介质:QSPI Flash / eMMC / SD卡 / RPC HyperFlash IPL从介质读取SPL → SPL从介质读取ATF+U-Boot 内存布局 IPL在内部SRAM → SPL在内部SRAM → ATF/U-Boot在DDR

2.3 IPL与SPL:第一口饭怎么吃

IPL是芯片出厂固化的,你改不了。但它会检查启动介质头部是否有合法的「启动描述符」。这个描述符里包含了SPL的加载地址、大小、校验和。

关键点: SPL必须放在介质的前几个扇区,且头部格式必须正确。否则IPL会认为介质无效,然后尝试下一个启动模式。

SPL的代码量一般控制在几十KB以内。为什么?因为内部SRAM通常只有128KB~256KB,你还要留一部分给ATF的BL2。我个人习惯,SPL里只做三件事:

  • 初始化DDR控制器(PFC、DDR PHY调校)
  • 初始化时钟(PLL、CPG)
  • 初始化PMIC(I2C通信,设置核心电压)

嗯,这里要注意。DDR初始化是SPL里最容易出问题的地方。我曾经在一块新板子上,DDR时序参数没配好,SPL加载ATF时直接卡死。后来用示波器量DQS信号才发现,走线等长没做好。

2.4 ATF:安全启动与异常等级

ATF是ARM生态里的标准组件。R-Car用的是Trusted Firmware-A。它负责把系统从EL3(安全监控模式)切换到EL2(虚拟机监控模式),最后交给U-Boot。

ATF在R-Car上主要干这几件事:

  1. BL2 —— 验证U-Boot的签名(如果使能了安全启动)。
  2. BL31 —— 提供PSCI接口,用于CPU开关、系统挂起/恢复。
  3. BL32 —— 可选,跑一个安全OS(如OP-TEE)。
我的建议: 刚开始移植时,先关掉安全启动验证。等U-Boot和内核都跑通了,再回头开签名校验。否则一旦签名不对,连错误信息都看不到。

2.5 U-Boot移植与配置

U-Boot是大家最熟悉的部分。但R-Car的U-Boot移植,有几个特殊之处。

2.5.1 设备树配置

R-Car的U-Boot使用设备树(DTB)来描述硬件。你需要确保以下节点配置正确:

  • CPG —— 时钟生成器,必须匹配板级晶振频率。
  • PFC —— 引脚功能控制器,复用关系不能错。
  • MMC/SD —— eMMC和SD卡控制器,时钟和电压要配好。
  • SCIF —— 串口,调试输出全靠它。

2.5.2 关键配置项

在U-Boot的defconfig里,有几个选项是必选的:

CONFIG_TARGET_RCAR_GEN3=y        # 或GEN4,取决于芯片
CONFIG_RCAR_IPMMU=y              # IOMMU,不配可能DMA异常
CONFIG_RCAR_DMA=y                # DMA控制器
CONFIG_RPC_HYPERFLASH=y          # 如果使用HyperFlash
CONFIG_MMC_SDHI=y                # eMMC/SD卡驱动
CONFIG_SCIF_CONSOLE=y            # 串口控制台
曾经踩过的坑: 我有一块板子,U-Boot启动时打印完「DRAM: 4 GiB」就死机了。查了两天,最后发现是IPMMU没使能,DMA访问越界导致总线错误。所以IPMMU一定要开。

2.5.3 编译与烧录

编译命令大致如下:

# 编译ATF
make -C trusted-firmware-a PLAT=rcar_gen3 bl2 bl31

# 编译U-Boot
make rcar_gen3_defconfig
make

# 生成启动镜像
tools/mkimage -T rcar_image -a 0x0 -e 0x0 -d u-boot.bin u-boot-rcar.img

烧录时,注意启动介质的偏移地址。QSPI Flash一般从0x0开始放SPL,0x1C000放ATF,0x20000放U-Boot。具体偏移看芯片手册。

2.6 避坑指南

最后,分享几个我实际项目中遇到的坑:

  • PMIC初始化顺序 —— 必须先给核心供电,再给DDR供电。顺序反了,DDR初始化必失败。
  • 时钟树配置 —— R-Car的PLL关系复杂。我曾经把CSI2(摄像头)的时钟配错了,导致整个系统时钟域混乱,U-Boot里网络都跑不起来。
  • 启动介质选择 —— 如果同时接了QSPI和eMMC,IPL会按优先级尝试。调试时建议只留一个介质,避免干扰。
  • 串口电平 —— R-Car的调试串口是1.8V电平,直接连USB转串口(3.3V)可能烧坏管脚。加个电平转换吧。

总结一下:R-Car的启动流程,核心就是「IPL→SPL→ATF→U-Boot」这条链。每一级都有明确的职责和约束。移植时,先从SPL和DDR初始化入手,再逐步加上ATF和U-Boot。别想着一步到位,分段验证最稳妥。