4. U-Boot移植与板级适配
U-Boot 是 TI Sitara(AM335x/AM437x/AM57xx 等)平台上电后运行的第一段可维护软件,它负责最基础的 DDR 初始化、时钟树配置、串口控制台输出、网络下载,以及把 Linux 内核与设备树加载到内存并跳转执行。所谓“移植”,本质上是把官方或 SoC 厂商提供的通用代码,裁剪、补充并绑定到我们自己这块板子的硬件事实上:DDR 颗粒型号与容量、晶振频率、启动介质顺序、PHY 型号与地址、引脚复用,以及量产时需要的启动脚本。本节围绕源码结构、board/SoC 配置、DDR 与时钟初始化、串口与网络适配、环境变量与启动脚本五条主线展开。
源码结构与板级配置的落点
U-Boot 采用“通用框架 + 板级目录”的组织方式。与移植关系最密切的目录包括:arch/arm/cpu/armv7/ 下的 SoC 级启动代码与时钟、DDR 控制器驱动;arch/arm/dts/ 下的设备树;board/ti/ 下的板级文件(如 board/ti/am335x/board.c、mux.c);drivers/ 下的串口、MMC、网络、PMIC 等驱动;configs/ 下的 *_defconfig;include/configs/ 下的板级头文件。现代 U-Boot 已大量使用 Kconfig 与设备树,因此“改板”通常不是改 C 代码,而是改 defconfig、设备树和板级初始化回调。
以 AM335x 为例,一个最小可用的板级适配流程是:先复制一份相近的 defconfig(如 am335x_evm_defconfig)重命名为 myboard_defconfig,在 board/ti/ 下建立自己的板目录并加入 Makefile 与 Kconfig,再在设备树中描述 DDR、UART、MMC、以太网等节点。编译时通过 make myboard_defconfig && make CROSS_COMPILE=arm-linux-gnueabihf- 生成 u-boot.img 与 MLO(SPL)。判断移植是否起步成功,最直接的依据是串口能否打印 SPL 与 U-Boot 的版本、DRAM 容量和启动介质信息。
DDR 与时钟初始化:最容易“起不来”的一步
SPL 阶段最关键的职责是配置 EMIF(外部存储器接口)并完成 DDR 训练。以 AM335x + DDR3 为例,需要根据颗粒手册填写 emif_regs 中的时序参数:SDTIM1、SDTIM2、SDCR、SDRCR 等。常见做法是使用 TI 提供的 AM335x EMIF Tool,输入晶振频率(如 24MHz)、DDR 时钟(如 400MHz)、颗粒容量(512MB)、位宽(16bit)和时序(CL=6、tRCD=6、tRP=6、tRAS=15),工具会输出一组寄存器值,再填入 board/ti/myboard/board.c 的 ddr3_data 结构体。
时钟初始化同样在 SPL 中完成。AM335x 的时钟树由 MPU_PLL、CORE_PLL、PER_PLL、DISP_PLL 等组成,通过 clocks_init() 设置倍频与分频。例如目标 MPU 600MHz、CORE 400MHz、DDR 400MHz,需要根据 24MHz 参考时钟计算 M/N/M2 分频值。若 DDR 初始化失败,串口通常只打印到 “SPL” 或 “U-Boot SPL” 后卡死,此时应优先检查 DDR 供电、VREF、颗粒焊接和时序参数,而不是怀疑内核。
串口与网络驱动适配
串口是移植的“眼睛”。AM335x 默认使用 UART0,引脚为 uart0_rxd/uart0_txd,需要在 mux.c 中调用 enable_uart0_pin_mux(),并在设备树中确认 &uart0 节点状态为 okay。控制台参数通常为 console=ttyO0,115200n8。若上电无任何输出,先确认串口线序(TX/RX 交叉)、波特率和 CONFIG_BAUDRATE 是否一致。
网络适配的重点是 CPSW 与 PHY。AM335x 内部集成双口 CPSW,外部通过 RGMII/MII 连接 PHY(如 KSZ9031、DP83848)。设备树中需要描述 &cpsw 的 phy-mode、phy-handle 和 PHY 地址;若 PHY 地址由硬件 strapping 决定,需在 board.c 中通过 cpsw_phy_sel 或 set_phy_control 修正。验证时使用 ping 命令,若出现 “No ethernet found” 或 “PHY not found”,应检查 MDIO 总线、PHY 复位引脚和 25MHz 时钟。
环境变量与启动脚本定制
U-Boot 环境变量决定了“怎么启动”。默认环境保存在 CONFIG_ENV_OFFSET 指定的 MMC 或 SPI Flash 区域。量产时通常把 bootcmd 定制为从 eMMC 加载内核与设备树,例如:
setenv bootcmd 'mmc dev 1; fatload mmc 1:1 0x82000000 zImage; fatload mmc 1:1 0x88000000 am335x-myboard.dtb; bootz 0x82000000 - 0x88000000'
setenv bootargs 'console=ttyO0,115200n8 root=/dev/mmcblk1p2 rw rootwait'
saveenv
若需要网络启动,可定义 bootcmd 为 dhcp ${loadaddr} zImage; tftp ${fdtaddr} myboard.dtb; bootz。建议把公共参数抽成 bootargs,把加载地址抽成 loadaddr、fdtaddr,便于维护。修改后务必执行 saveenv,否则重启即丢失。判断启动脚本是否生效,可观察串口是否打印 “Starting kernel ...”,以及内核是否成功挂载根文件系统。