RK3568 开发实战:定制 u-boot SPL 的 eMMC 启动优先级
1. 理解RK3568的启动流程与SPL机制在嵌入式开发中RK3568这类SoC的启动过程往往比PC更加复杂。我第一次接触RK3568开发板时就被它的多阶段启动流程搞得一头雾水。简单来说RK3568的启动分为几个关键阶段ROM代码加载SPLSecondary Program LoaderSPL加载u-boot最后u-boot加载操作系统内核。SPL在这里扮演着关键角色它相当于u-boot的精简版主要职责是初始化最基本的硬件比如DDR、时钟、eMMC等然后加载完整版的u-boot。在实际项目中我发现很多开发者容易忽略SPL的配置直到遇到启动问题才开始重视。以正点原子ATK-DLRK3568开发板为例默认的SPL启动顺序是MMC2 - MMC1而开发板的eMMC实际连接在MMC1上这就导致了每次启动时都会先尝试从MMC2启动失败后才回退到MMC1不仅拖慢启动速度还会在串口日志中看到一堆报错信息。要验证这个问题可以在u-boot启动时按CTRLC中断自动启动流程然后输入mmc info命令。在我的测试中输出显示当前使用的是sdhcife310000这个设备对应开发板上的eMMC接口。通过设备树可以确认这个设备在系统中被标记为MMC1。理解这个映射关系是解决问题的第一步。2. 定位eMMC启动顺序问题的技术细节当我在正点原子开发板上第一次看到MMC2启动失败的报错时第一反应是硬件连接有问题。但经过仔细排查发现这是SPL的默认配置导致的。RK3568的SPL内置了一套设备启动顺序逻辑它会按照预设的列表逐个尝试直到找到可启动的设备。要深入理解这个问题我们需要查看设备树中的关键配置。在RK3568的u-boot源码中rk3568-u-boot.dtsi文件定义了默认的启动顺序。通过搜索spl-boot-order这个关键词可以找到如下配置片段chosen { stdout-path uart2; u-boot,spl-boot-order sdmmc0, sdhci, nandc0, spi_nand, spi_nor; };这个配置意味着SPL会先尝试从sdmmc0对应MMC2启动失败后再尝试sdhci对应MMC1。对于正点原子的开发板来说这个顺序显然不太合理因为板上根本没有连接MMC2设备。为了验证这一点我使用了u-boot的mmc list命令输出显示MMC0: 0 (SD卡) MMC1: 1 (eMMC)这清楚地说明了设备编号与实际硬件的对应关系。在开发过程中这种细节往往容易被忽视但却对系统行为产生重大影响。3. 修改设备树配置调整启动顺序确定了问题根源后我开始着手修改SPL的启动顺序。这个过程需要修改u-boot的设备树源文件具体路径是arch/arm/dts/rk3568-u-boot.dtsi。找到chosen节点后将spl-boot-order中的sdhci调整到第一位chosen { stdout-path uart2; u-boot,spl-boot-order sdhci, sdmmc0, nandc0, spi_nand, spi_nor; };这个修改看似简单但有几个技术细节需要注意设备树中的节点引用如sdhci必须与实际的设备树节点定义一致修改后需要重新编译SPL和u-boot不同版本的u-boot可能对设备树语法有细微差别在我的实际操作中发现正点原子提供的Linux SDK中的u-boot版本对设备树处理有些特殊。为了确保修改生效我采用了完整的编译流程# 设置交叉编译工具链 export PATH$PATH:/path/to/gcc-arm-8.3-2019.03-x86_64-aarch64-linux-gnu/bin # 清理旧编译结果 make mrproper # 使用开发板配置 make atk_dlrk3568_defconfig # 编译SPL和u-boot ./make.sh --spl编译完成后将生成的idbloader.img和u-boot.itb烧写到开发板重启后观察串口输出发现不再有MMC2的报错信息启动时间也明显缩短了约200ms。这个改进对于需要快速启动的应用场景如工业控制设备尤为重要。4. 独立编译u-boot的实用技巧在实际开发中我们经常需要单独编译u-boot而不是整个Linux SDK。这对于快速迭代和调试特别有用。基于我在正点原子RK3568开发板上的经验总结了一套可靠的独立编译方法首先需要准备好正确的配置文件。虽然可以直接使用SDK中的.config但我推荐生成一个精简的defconfig# 在u-boot根目录下 make ARCHarm CROSS_COMPILEaarch64-linux-gnu- savedefconfig cp defconfig configs/atk_dlrk3568_defconfig其次设备树文件也需要特别处理。正点原子的开发板默认使用rk3568-evb.dts但为了更好的维护性建议创建专属的设备树文件cp arch/arm/dts/rk3568-evb.dts arch/arm/dts/atk_dlrk3568.dts然后通过menuconfig设置默认设备树make ARCHarm CROSS_COMPILEaarch64-linux-gnu- menuconfig在图形界面中找到Device Tree Control - (atk-dlrk3568) Default Device Tree for DT control最后使用开发板专属的编译脚本会更方便。可以修改make.sh脚本添加针对ATK-DLRK3568的编译选项#!/bin/bash BOARDatk_dlrk3568 TOOLCHAINaarch64-linux-gnu- export CROSS_COMPILE$TOOLCHAIN make $BOARD_defconfig make -j$(nproc)这套方法在我的多个RK3568项目中都验证有效特别是在需要频繁修改u-boot配置的情况下可以节省大量编译时间。需要注意的是不同版本的u-boot可能会有细微差异如果遇到问题建议查阅对应版本的Rockchip官方文档。5. 调试与验证启动顺序修改效果修改SPL启动顺序后如何验证修改确实生效了这是很多开发者容易忽略的关键步骤。在我的项目中总结了几种有效的验证方法第一种方法是观察串口输出。未修改前启动日志中会明确显示尝试MMC2失败的记录Trying to boot from MMC2 MMC: no card present修改后这些错误信息应该消失直接显示从MMC1启动。第二种方法是使用u-boot的命令行工具。启动时按任意键中断自动启动然后输入mmc dev 1 mmc info这会显示当前选中的MMC设备详细信息确认是否是开发板上的eMMC。第三种更专业的方法是测量启动时间。使用示波器测量系统复位信号到第一个内核消息的时间差。在我的测试中优化启动顺序后整体启动时间缩短了约15%这是因为跳过了不必要的设备检测过程。为了更系统地评估修改效果我制作了一个对比表格测试项修改前修改后改进效果MMC2错误信息存在消失日志更干净启动时间1.2s1.0s快200ms系统稳定性偶尔超时稳定可靠性提升这些实测数据可以帮助开发者评估修改的实际价值。特别是在产品量产阶段这种优化虽然微小但累积起来可能对用户体验产生显著影响。6. 深入理解Rockchip平台的u-boot定制经过这个项目的实践我对Rockchip平台的u-boot有了更深的理解。与通用u-boot相比Rockchip的版本做了不少针对性的优化和改动这也是为什么官方建议直接使用他们的u-boot而不是vanilla版本。一个典型的例子是SPL的实现。Rockchip的SPL不仅处理启动顺序还包含了许多芯片特有的初始化代码比如DDR控制器配置、PMIC管理等。这些代码通常存放在arch/arm/mach-rockchip目录下。在修改启动顺序时最好先了解这些底层机制避免引入不兼容问题。另一个需要注意的点是设备树的处理。Rockchip平台使用了一套扩展的设备树绑定比如u-boot,spl-boot-order就是他们自定义的属性。在移植或升级u-boot版本时这些非标准属性可能会发生变化需要特别关注。基于我的经验对于RK3568这类复杂SoC我有几个建议尽量使用芯片厂商提供的u-boot版本修改前先充分理解现有机制保持修改最小化只改动必要部分做好版本控制记录每次修改的内容和目的这些原则不仅适用于启动顺序的调整也适用于其他u-boot定制工作。记住在嵌入式开发中稳定性往往比功能丰富性更重要。