1. RK3568内核启动流程全景解析
作为瑞芯微新一代中高端通用型SoC,RK3568凭借四核Cortex-A55架构和Mali-G52 GPU,在工业控制、边缘计算和多媒体处理领域广受欢迎。但要让这块芯片真正运转起来,理解其内核启动流程是每位开发者的必修课。今天我就结合自己调试正点原子RK3568开发板的实战经验,带大家深入这个"黑匣子"内部。
内核启动不是简单的通电即用,而是一场精心编排的接力赛。从按下电源键到Linux内核接管系统,RK3568需要经历五个关键阶段:BootROM→SPL→TPL→U-Boot→Linux Kernel。每个阶段都有其独特使命,就像接力赛中每位选手负责不同的赛段。下面这张时序图能帮你建立整体认知:
code复制[电源启动]
│
▼
BootROM (固化在芯片中的第一段代码)
│
▼
SPL (Secondary Program Loader)
│
▼
TPL (Tertiary Program Loader)
│
▼
U-Boot (全功能Bootloader)
│
▼
Linux Kernel
2. 启动阶段深度拆解
2.1 BootROM:芯片的"出厂设置"
当开发板通电瞬间,CPU所有寄存器都会被复位,此时BootROM(又称Mask ROM)这个固化在芯片内部的微程序开始接管。它的核心职责就像机场的登机引导员:
-
启动介质检测:依次扫描SPI Flash、eMMC、SD卡等存储设备,寻找有效的启动镜像。正点原子开发板通常配置从eMMC启动,其检测顺序可通过芯片的Boot Mode引脚配置。
-
安全校验:验证第一级引导程序(通常是SPL)的数字签名,防止恶意代码注入。RK3568支持安全启动(Secure Boot)模式,此时会校验RSA2048签名。
调试技巧:通过串口终端在启动时按住Ctrl+C,可进入BootROM的下载模式,这时能用Rockchip提供的rkdeveloptool工具烧写镜像。
2.2 SPL/TPL:内存的"搬运工"
BootROM之后,系统会加载SPL(Secondary Program Loader)。由于BootROM阶段DRAM尚未初始化,SPL需要在不大于256KB的代码空间内完成:
-
时钟树配置:初始化PLL锁相环,设置CPU/GPU/总线时钟。RK3568的时钟体系相当复杂,涉及APLL/BPLL/CPLL等多个PLL源。
-
DDR初始化:根据板载内存颗粒型号(如美光D9ZCL),配置时序参数。这是最容易出问题的环节,正点原子提供的
rk3568-dram-lpddr4x-1066.dtsi包含了已验证的参数。
c复制// 典型DDR配置代码片段(来自U-Boot源码)
static struct rk3568_ddr_dts_config ddr_config = {
.ddr_freq = 1056*MHz,
.lpddr4x_dq_odt = 0x40,
.phy_lpddr4x_ca_drv = 0x1b,
.phy_lpddr4x_dq_drv = 0x15
};
- 加载TPL:初始化基础外设(如串口、GPIO)后,SPL会从存储设备加载更大的TPL(Tertiary Program Loader)到内存。TPL继续完成:
- 更复杂的外设初始化(如PCIe、USB3.0)
- 存储设备完整驱动(如eMMC的HS400模式)
- 准备U-Boot运行环境
2.3 U-Boot:系统的"总指挥"
当TPL完成使命后,全功能的U-Boot开始接管。RK3568平台通常使用Rockchip定制的U-Boot版本,其主要任务包括:
-
设备树解析:加载
rk3568-evb.dtb这样的设备树文件,描述硬件拓扑。开发中经常需要修改dts文件来适配自定义硬件。 -
多镜像加载:通过Rockchip特有的
rockchip-kernel.img格式,同时加载内核镜像和initramfs。一个典型的加载命令如下:
bash复制# U-Boot环境变量示例
load mmc 0:1 0x00280000 /boot/Image
load mmc 0:1 0x05a00000 /boot/rk3568-evb.dtb
booti 0x00280000 - 0x05a00000
- 启动参数传递:通过
bootargs环境变量向内核传递参数,例如:bash复制
setenv bootargs console=ttyFIQ0,1500000 root=/dev/mmcblk1p5 rootwait
避坑指南:如果遇到内核启动后卡住,可以尝试在U-Boot中使用
printenv检查bootargs是否正确,特别是控制台设备和rootfs路径是否与实际硬件匹配。
3. Linux内核接管后的关键动作
当U-Boot执行booti命令后,CPU会跳转到内核入口地址,开始Linux的启动流程。RK3568内核启动有几个特殊点值得关注:
3.1 多核启动流程
RK3568的四个Cortex-A55核心并非同时启动,而是采用主从模式:
- CPU0作为主核首先运行,执行
head.S中的汇编代码,初始化MMU和缓存。 - 在
smp_prepare_cpus阶段,主核通过写CRU_MODE_CON寄存器唤醒其他三个从核。 - 从核启动后会执行
secondary_startup,等待调度器分配任务。
c复制// 内核源码中的CPU热插拔示例(arch/arm64/kernel/smp.c)
static void __init smp_cpu_setup(int cpu)
{
if (cpu == 0) {
/* 主核特殊初始化 */
} else {
/* 从核通过PSCI接口启动 */
if (psci_ops.cpu_on(cpu_logical_map(cpu), __pa_symbol(secondary_entry)))
pr_err("failed to boot CPU%d\n", cpu);
}
}
3.2 外设初始化顺序
RK3568的芯片手册中明确规定了各模块的初始化顺序要求:
- 电源管理域:先初始化VDD_LOGIC(逻辑电路供电),再配置VDD_GPU(GPU供电)。
- 时钟系统:APLL必须早于BPLL初始化,否则会导致PCIe时钟失锁。
- PHY层设备:USB3.0 PHY需要在控制器初始化前完成校准。
3.3 典型问题排查
在实际开发中,经常会遇到以下启动问题:
问题1:内核卡在"Starting kernel..."
- 检查点:
- U-Boot的
booti参数是否正确(特别是设备树地址) - 内核镜像是否包含正确的设备树(可用
fdtdump工具验证) - 串口波特率是否匹配(RK3568通常使用1500000bps)
- U-Boot的
问题2:DRAM容量识别不全
- 解决方法:
- 检查SPL阶段的DDR初始化参数
- 确认板载内存颗粒型号与配置匹配
- 使用
dmidecode -t memory命令验证
问题3:二级CPU核心未启动
- 排查步骤:
- 检查内核配置是否启用
CONFIG_SMP - 查看
/proc/cpuinfo确认所有核心可见 - 测量各核心供电电压是否正常
- 检查内核配置是否启用
4. 定制化启动方案实战
4.1 安全启动配置
RK3568支持基于硬件加密的安全启动流程,具体实现步骤:
-
生成RSA密钥对:
bash复制openssl genrsa -out private_key.pem 2048 openssl rsa -in private_key.pem -pubout -out public_key.pem -
在U-Boot中编译进公钥:
c复制#include <asm/arch-rockchip/secure_boot.h> const unsigned char rsa_public_key[] = { /* 粘贴public_key.pem内容 */ }; -
使用rkdeveloptool签名镜像:
bash复制
rkdeveloptool sign-image Image --private-key private_key.pem --output Image.signed
4.2 快速启动优化
针对工业控制等需要快速启动的场景,可以通过以下手段优化:
-
SPL加速:
- 启用
CONFIG_SPL_FRAMEWORK的快速路径 - 预计算DDR时序参数,避免运行时校准
- 启用
-
内核裁剪:
- 使用
make tinyconfig创建最小配置 - 禁用不需要的驱动和模块
- 使用
-
Initramfs整合:
bash复制# 将内核与initramfs打包 mkimage -A arm64 -O linux -T kernel -C none -a 0x00280000 -e 0x00280000 \ -d Image -n "Linux Kernel" kernel.img
4.3 双系统启动方案
利用RK3568的eMMC和SD卡槽,可以实现A/B双系统切换:
-
分区方案示例:
code复制/dev/mmcblk0p1: SPL /dev/mmcblk0p2: U-Boot /dev/mmcblk0p3: System A (kernel+rootfs) /dev/mmcblk0p4: System B (kernel+rootfs) -
U-Boot切换脚本:
bash复制# 在U-Boot环境中定义切换命令 setenv bootcmd "if test ${bootcount} -gt 3; then mmc dev 0; ext4load mmc 0:4 0x00280000 /boot/Image; else mmc dev 0; ext4load mmc 0:3 0x00280000 /boot/Image; fi; booti 0x00280000 - 0x05a00000"
在调试RK3568启动流程时,我强烈建议配备一个USB转串口调试器,通过查看完整的启动日志能快速定位问题阶段。当遇到特别棘手的问题时,可以尝试用示波器测量关键电源轨的上电时序,很多时候启动失败仅仅是某个电源未按正确顺序使能导致的。
