2. i.MX硬件平台与启动链路

i.MX6/7/8系列虽然同属NXP的ARM应用处理器家族,但三代SoC在启动架构上的差异,直接决定了BSP移植时哪些代码需要改、哪些可以复用。理解启动链路的关键,不是背下每个阶段的名字,而是搞清楚“谁把谁加载到哪、用什么格式描述、失败时从哪里恢复”。

一、三代SoC的架构差异与启动介质

i.MX6采用ARM Cortex-A9(单核到四核),内部集成OCRAM、ROM、MMDC(DDR控制器)和各类外设控制器。i.MX7是异构双核架构:Cortex-A7负责运行Linux,Cortex-M4负责实时任务,两者通过MU(Messaging Unit)通信。i.MX8系列进一步分化为i.MX8M(A53+M4)、i.MX8Quad(A72+A53)、i.MX8X等子系列,启动链中引入了SCU(System Controller Unit)和更复杂的电源域管理。

启动介质方面,i.MX6/7支持eFUSE和GPIO拨码选择启动源,常见的有SD/eMMC、NAND、NOR、QSPI、串行下载(Serial Download)。i.MX8M系列则通过BOOT_MODE引脚和eFUSE组合决定启动源,且引入了容器格式(Container)来封装多份镜像。这个差异意味着:i.MX6的裸镜像可以直接写入SD卡偏移处启动,而i.MX8M通常需要先用mkimage工具生成容器镜像。

二、Boot ROM:芯片出厂固化的第一段代码

Boot ROM是SoC上电后执行的第一段代码,固化在芯片内部,不可修改。它的职责非常明确:读取启动模式引脚/eFUSE,初始化最基本的时钟和启动介质控制器,从启动介质中读取头部信息,验证并加载下一阶段镜像到片内RAM(i.MX6为OCRAM,i.MX8M为TCML/TCMU),然后跳转执行。

Boot ROM的容错机制值得关注:如果从主启动介质加载失败(如IVT校验不通过、DCD执行出错),Boot ROM会尝试备用启动介质;如果所有介质都失败,则进入串行下载模式(USB HID/MSC),等待主机通过mfgtool或uuu工具下发镜像。这个机制在板子“变砖”时是最后的恢复手段。

三、IVT与DCD:Boot ROM能读懂的“说明书”

Boot ROM不认识ELF、不认识文件系统,它只认一种固定格式:IVT(Image Vector Table)+ Boot Data + DCD(Device Configuration Data)。IVT是镜像头部的入口结构,包含自地址、Boot Data地址、DCD地址、入口地址等字段。Boot ROM通过IVT定位到各个子结构,再按DCD的指令序列初始化DDR等外设。

DCD本质上是一段由Boot ROM解释执行的“寄存器写入脚本”,格式为“命令+地址+值”的序列。它通常由NXP的DDR配置工具(如i.MX6的DDR Stress Test、i.MX8M的DDR Tool)根据具体DDR颗粒参数生成。DCD执行完毕后,DDR才可用,Boot ROM才能把更大的镜像(如U-Boot SPL)加载到DDR中。

关键适配点:更换DDR颗粒型号或容量时,必须重新生成DCD。DCD错误会导致Boot ROM在初始化DDR时挂死,表现为串口无任何输出,此时只能通过串行下载模式恢复。

四、SPL/U-Boot:从最小系统到完整引导

由于Boot ROM能加载的镜像大小有限(i.MX6通常限制在OCRAM容量内),U-Boot被拆分为SPL(Secondary Program Loader)和完整U-Boot两阶段。SPL运行在片内RAM中,体积小,只做最必要的事:初始化串口(用于调试输出)、初始化DDR(如果DCD未完成)、从启动介质读取完整U-Boot到DDR、跳转执行。

完整U-Boot运行在DDR中,负责更复杂的初始化:网络、USB、显示、环境变量、设备树加载,最终引导Linux内核。在i.MX8M上,由于ATF(ARM Trusted Firmware)的介入,启动链变为:Boot ROM → SPL → ATF → U-Boot → Linux。SPL加载ATF和U-Boot,ATF运行在EL3(安全监控模式),负责建立安全环境后再跳转到U-Boot的EL2或EL1。

五、ATF与OP-TEE:安全启动的引入

ATF(ARM Trusted Firmware)实现了ARMv8的异常等级切换和PSCI(Power State Coordination Interface),负责CPU上下电、系统复位等底层电源管理。OP-TEE则运行在安全世界(Secure World),提供可信执行环境,用于密钥管理、DRM、安全存储等场景。

在i.MX8M的启动链中,ATF通常以BL31的形式被SPL加载,OP-TEE以BL32的形式加载。U-Boot作为BL33运行在非安全世界。设备树中需要通过firmware节点声明ATF和OP-TEE的入口地址与内存保留区域。适配时需注意:如果不需要安全功能,可以裁剪OP-TEE以减小镜像体积;但ATF通常是必需的,因为PSCI和电源管理依赖它。

i.MX8M 启动链路与镜像结构 Boot ROM → SPL → ATF(BL31) → U-Boot(BL33) → Linux | OP-TEE(BL32) 并行加载 Boot ROM 芯片固化 · 不可修改 读引脚/eFUSE → 选启动源 IVT 镜像头 · 入口地址 Boot Data · DCD指针 DCD 寄存器写入脚本 初始化DDR/时钟 启动介质 SD / eMMC / QSPI NAND / 串行下载 阶段二:SPL 加载与安全固件 SPL 运行于片内RAM 初始化串口/DDR 加载ATF+U-Boot到DDR ATF (BL31) EL3安全监控 PSCI电源管理 异常等级切换 OP-TEE (BL32) 安全世界运行 密钥/DRM/安全存储 可选裁剪 并行加载 阶段三:U-Boot 与内核引导 U-Boot (BL33) 运行于DDR · 非安全世界 网络/USB/显示初始化 加载内核+设备树 Linux Kernel 解压内核 · 挂载根文件系统 驱动初始化 · 用户空间启动 典型内存布局(示例) ATF: 0x00900000 | OP-TEE: 0x00A00000 U-Boot: 0x40200000 | Kernel: 0x40400000 DTB: 0x43000000 | RootFS: 由内核参数指定 失败恢复路径: 主介质IVT/DCD校验失败 → 尝试备用介质 → 全部失败 → 进入串行下载模式(USB HID/MSC) 恢复工具:i.MX6/7 使用 mfgtool | i.MX8M 使用 uuu (Universal Update Utility)

六、适配关注点与常见问题

在实际BSP适配中,启动链路的调试通常从串口输出入手。如果上电后串口无任何输出,首先检查DCD是否正确——DDR初始化失败会导致Boot ROM挂死。如果SPL有输出但U-Boot无输出,检查SPL加载U-Boot的地址是否与DDR布局冲突。如果U-Boot能启动但内核挂死,检查设备树中firmware节点和内存保留区域是否与ATF/OP-TEE的实际加载地址一致。

另一个高频问题是启动介质的选择。i.MX6通过GPIO拨码或eFUSE选择,i.MX8M通过BOOT_MODE引脚配合eFUSE。量产时通常将eFUSE烧录为固定启动源,但开发阶段建议保留拨码开关以便切换。此外,i.MX8M的容器镜像需要正确设置CONTAINER和IMG_TYPE参数,否则Boot ROM无法识别。

调试建议:在SPL和U-Boot中分别加入版本打印和阶段标记,通过串口日志可以快速定位启动卡在哪个阶段。对于DDR问题,优先使用NXP官方DDR工具生成DCD,不要手动修改寄存器值。

总结来说,i.MX6/7/8的启动链路是“Boot ROM → IVT/DCD → SPL → U-Boot → Linux”的逐步扩展,i.MX8M在此基础上插入了ATF和OP-TEE。适配的核心工作是:根据DDR颗粒生成正确的DCD、根据内存布局配置SPL和U-Boot的加载地址、根据安全需求决定是否集成OP-TEE,以及确保设备树中的firmware节点与实际镜像地址一致。