4. U-Boot 移植与配置
Agilex SoC 的启动链是 BootROM → U-Boot SPL → ATF(BL31)→ U-Boot proper → Linux,其中 U-Boot 承担了 DDR 初始化、外设早期初始化、镜像加载与启动参数传递等关键职责。与通用 ARM 开发板不同,Agilex 的 U-Boot 移植必须同时处理 HPS(Hard Processor System)侧的 DDR 控制器、SDM(Secure Device Manager)握手、FPGA 配置加载以及多级启动镜像的拼接。本节围绕板级文件、设备树、DDR 初始化、启动参数与脚本定制五个方面展开,给出可直接参考的移植路径。
一、板级文件:从 Altera 参考板派生
U-Boot 源码中 Altera Agilex 相关板级目录位于 board/altera/ 下,常见参考板包括 socfpga_agilex、socfpga_agilex_socdk 等。移植到自定义板卡时,推荐以最接近的参考板为基线派生,而不是从零创建。核心文件包括:
board/altera/socfpga_agilex/:板级初始化代码,含spl.c、board.c、Makefile、Kconfig。configs/socfpga_agilex_defconfig:默认配置,定义CONFIG_TARGET_SOCFPGA_AGILEX、CONFIG_SPL_*等。arch/arm/dts/socfpga_agilex.dtsi:SoC 级设备树,描述 HPS 外设、时钟、复位、DDR 控制器节点。arch/arm/dts/socfpga_agilex_socdk-u-boot.dtsi:U-Boot 专用补充节点,如u-boot,dm-pre-reloc标记。
派生时需修改 Kconfig 中的 TARGET_* 名称、defconfig 中的 DEFAULT_DEVICE_TREE,并在 board/altera/ 下新增目录。板级 board_init() 中通常需要调用 socfpga_bridges_reset() 释放 HPS-FPGA 桥接,以及 cm_basic_init() 完成时钟管理器基础配置。
二、设备树:HPS 外设与 U-Boot 专用节点
Agilex 的 U-Boot 设备树分为三层:SoC 级 socfpga_agilex.dtsi、板级 socfpga_agilex_、U-Boot 补充 -u-boot.dtsi。板级 dts 中需要根据实际硬件修改:
memory@0节点:DDR 容量与起始地址,Agilex HPS 通常为0x0起始,容量 2GB/4GB/8GB 可选。mmc0:SD/MMC 控制器,指定bus-width、sdhci-caps-mask、no-1-8-v等。gmac0/gmac1:以太网,配置phy-mode(rgmii/sgmii)、phy-handle、snps,reset-gpio。uart0:调试串口,指定clock-frequency与current-speed。qspi:QSPI 闪存,用于存放 U-Boot 与 FPGA 配置镜像。
U-Boot 专用节点需在 -u-boot.dtsi 中为 SPL 阶段使用的设备添加 u-boot,dm-pre-reloc;,否则 SPL 无法在重定位前访问该设备。例如串口、时钟、DDR 控制器节点必须标记。若遗漏,典型现象是 SPL 阶段串口无输出或 DDR 初始化失败后无任何日志。
三、DDR 初始化:SPL 中的关键路径
Agilex 的 DDR 初始化由 SPL 调用 sdram_init() 完成,实际参数来自 Altera 提供的 sequencer 与 iocsr 配置。移植时最关键的输入是 Quartus 工程导出的 board_config 文件(如 socfpga_agilex_socdk_board_config.h),其中包含 DDR 时序参数、IO 延迟、PHY 设置。这些参数由 Quartus 的 EMIF IP 根据具体 PCB 走线生成,不能手工猜测。
典型流程为:在 Quartus 中配置 HPS 与 EMIF,生成 u-boot-spl.dtsi 与 board_config,将其放入 U-Boot 源码对应目录,重新编译 SPL。若 DDR 参数错误,SPL 会在 sdram_init() 后卡死或打印 DDR: Failed to init。可通过串口观察 SPL 是否输出 DDR: 前缀日志判断进度。
四、启动参数与脚本定制
U-Boot proper 阶段通过 bootargs 向 Linux 传递参数,Agilex 常用参数包括:
setenv bootargs "console=ttyS0,115200 root=/dev/mmcblk0p2 rw rootwait \
earlycon=uart8250,mmio32,0xffc02000 \
fpga_manager.fpga_firmware=agilex.rbf"
其中 earlycon 的地址必须与设备树中 uart0 的 reg 一致;fpga_manager.fpga_firmware 指定 FPGA 配置文件,由 Linux 的 FPGA Manager 在启动后加载。若使用 QSPI 启动,root= 应改为 /dev/mtdblock* 或使用 initramfs。
启动脚本通常放在 include/configs/socfpga_agilex.h 的 CONFIG_BOOTCOMMAND 中,或使用 boot.scr。推荐将启动逻辑写入 boot.scr,便于现场修改而无需重编译 U-Boot。示例脚本:
setenv bootargs "console=ttyS0,115200 root=/dev/mmcblk0p2 rw rootwait"
fatload mmc 0:1 ${kernel_addr_r} Image
fatload mmc 0:1 ${fdt_addr_r} socfpga_agilex_custom.dtb
booti ${kernel_addr_r} - ${fdt_addr_r}
脚本编译使用 mkimage -A arm64 -O linux -T script -C none -d boot.cmd boot.scr,放入 FAT 分区即可。
五、移植顺序与验证要点
建议按以下顺序推进,每步都有明确的观察点:
- 派生板级目录与 defconfig:复制参考板目录,重命名
TARGET_*,修改DEFAULT_DEVICE_TREE。编译后确认u-boot-with-spl.sfp生成。 - 修改板级 dts 与 -u-boot.dtsi:按实际硬件调整 memory、mmc、gmac、uart 节点,为 SPL 所需设备添加
u-boot,dm-pre-reloc。 - 导入 Quartus board_config 完成 DDR:将 EMIF 生成的参数文件放入对应目录,重新编译 SPL。串口应出现
DDR:日志且不卡死。 - 配置 bootargs 与 boot.scr:确认
earlycon地址与 dts 中 uart0 的reg一致,root=指向正确分区。 - 串口验证三级日志:SPL 输出 DDR 与时钟信息,U-Boot proper 输出板级信息与启动脚本执行过程,Linux 输出 earlycon 与根文件系统挂载信息。
- 固化到 QSPI 或 SD 卡:使用
quartus_pfg或mkpimage生成启动镜像,写入 QSPI;或直接将boot.scr、Image、dtb 放入 SD 卡 FAT 分区。
-u-boot.dtsi 中 uart0 是否标记 u-boot,dm-pre-reloc,以及 CONFIG_DEBUG_UART 是否使能。若 DDR 初始化失败,核对 board_config 是否与当前 PCB 版本匹配,必要时用 Quartus 重新生成。若 Linux 启动后无 earlycon 输出,检查 earlycon 地址是否与 dts 中 uart0 的 reg 一致,Agilex 常见为 0xffc02000。