实现动态设备树
RK3566 Buildroot 动态设备树加载功能 - 完整调试日志
平台: TaishanPi RK3566 | Kernel 6.1 | Linux SDK
日期: 2026-03-25
参考文档:
实现动态设备树.md (基于RK3576 TaishanPi-3的补丁)
https://doc.embedfire.com/linux/rk356x/driver/zh/latest/linux_driver/base_dynamic_device_tree.html
【第一阶段】初始实现 - 移植RK3576补丁到RK3566
补丁来源: LinuxSDK动态设备树插件补丁_20251224.zip (基于RK3576)
---- 新增文件 ----
u-boot/arch/arm/mach-rockchip/overlay_loader.c [新增]
核心加载器,U-Boot阶段从rootfs读取/boot/ubootEnv.txt
解析overlays=配置,加载/boot/overlays/*.dtbo
调用fdt_overlay_apply_verbose()合并到主设备树
支持最大128个overlay,每个最大256KB
使用堆内存分配(malloc),不使用栈
u-boot/arch/arm/include/asm/arch-rockchip/overlay_loader.h [新增]
头文件,声明 rockchip_load_dtbo_overlays(void *fdt_addr)
kernel-6.1/arch/arm64/boot/dts/rockchip/device-tree-overlays/Makefile [新增]
overlay编译系统,两步编译:CPP预处理 + DTC编译
支持#include语法
kernel-6.1/arch/arm64/boot/dts/rockchip/device-tree-overlays/ubootEnv.txt [新增]
用户配置模板,overlays=行指定要加载的dtbo文件
kernel-6.1/arch/arm64/boot/dts/rockchip/device-tree-overlays/overlays/leds-test.dts [新增]
示例overlay
device/rockchip/common/post-hooks/92-overlays.sh [新增]
rootfs打包时将ubootEnv.txt和*.dtbo安装到/boot
---- 修改文件 ----
u-boot/arch/arm/mach-rockchip/Makefile [修改]
obj-$(CONFIG_OF_LIBFDT_OVERLAY) += overlay_loader.o
u-boot/arch/arm/mach-rockchip/boot_rkimg.c [修改]
extern声明 rockchip_load_dtbo_overlays
在rockchip_read_dtb_file()末尾调用 rockchip_load_dtbo_overlays()
u-boot/configs/rk3568_defconfig [修改]
CONFIG_OF_LIBFDT_OVERLAY=y (启用FDT overlay支持)
CONFIG_DISTRO_DEFAULTS=y (启用distro默认配置,含fs支持)
~ CONFIG_BOOTDELAY=0 → 2 (留出U-Boot交互时间)
device/rockchip/common/scripts/mk-kernel.sh [修改]
kernel编译后自动编译device-tree-overlays目录下的overlay
将ubootEnv.txt和*.dtbo复制到$RK_OUTDIR/overlays
【BUG #1】FDT_ERR_NOTFOUND - overlay目标节点不存在
现象:
串口日志显示:
failed on fdt_overlay_apply(): FDT_ERR_NOTFOUND
[leds-test.dtbo] Failed to apply overlay: FDT_ERR_NOTFOUND
根因分析:
示例overlay leds-test.dts中: target = <&backlight>
但RK3566的设备树tspi-rk3566-user-v10-linux.dts中:
- tspi-rk3566-dsi-v10.dtsi (含backlight定义) 被注释 (第36行)
- tspi-rk3566-edp-v10.dtsi (含backlight定义) 被注释 (第33行)
→ 最终设备树中不存在backlight标签
修复:
将leds-test.dts的目标改为设备树中确实存在的节点:
target = <&backlight> → target = <&leds>
leds节点在tspi-rk3566-user-v10-linux.dts第59行定义,status="okay"
【BUG #2】kernel目录放错 - 应为kernel-6.1
现象:
overlay文件放在了kernel/目录下,但实际SDK使用的是kernel-6.1/
根因分析:
SDK根目录下有两个目录:
kernel/ ← 普通目录(可能是旧版本或符号链接目标)
kernel-6.1/ ← 实际使用的kernel 6.1源码目录
初始实现误将device-tree-overlays创建在kernel/下
修复:
删除 kernel/arch/arm64/boot/dts/rockchip/device-tree-overlays/
在 kernel-6.1/arch/arm64/boot/dts/rockchip/device-tree-overlays/ 下重新创建:
Makefile
ubootEnv.txt
overlays/leds-test.dts (已使用修正后的<&leds>目标)
【BUG #3】Sysmem Error: Failed to double alloc for existence "FDT"
现象:
overlay加载成功 (Applied 1 of 1),但紧接着:
系统无法启动,进入错误恢复循环。
根因分析:
rockchip_read_dtb_file()中的执行顺序:
1. sysmem_alloc_base(MEM_FDT, fdt, size + PAD) ← 按原始DTB大小(~176KB)分配
2. rockchip_load_dtbo_overlays()
→ fdt_increase_size(fdt, overlay_count * 32KB) ← FDT扩大32KB+
3. FIT启动时再次尝试分配"FDT"区域 → 大小冲突 → 崩溃
sysmem_alloc_base先记录了原始FDT大小,但overlay_loader通过fdt_increase_size
将FDT扩大超出了已分配区域,导致后续FIT启动检测到内存区域冲突。
修复:
调整boot_rkimg.c中rockchip_read_dtb_file()的执行顺序:
将overlay加载移到sysmem_alloc_base之前,使分配时FDT已经是最终大小。
修改前:
sysmem_alloc_base() ← 按小尺寸分配
rk_board_early_fdt_fixup()
android_fdt_overlay_apply()
rockchip_load_dtbo_overlays() ← FDT变大,超出分配
修改后:
rk_board_early_fdt_fixup()
android_fdt_overlay_apply()
rockchip_load_dtbo_overlays() ← FDT先扩大
sysmem_alloc_base() ← 按最终大尺寸分配
【BUG #4】Overlay加载成功但实际未生效 - FIT启动覆盖DTB
现象:
串口日志显示overlay成功应用:
[leds-test.dtbo] Applied successfully
Summary: Applied 1 of 1 overlay(s)
但LED硬件仍正常运行,status="disabled"未生效。
根因分析:
分析完整启动日志发现FIT启动流程:
第5855行: RESC: 'boot' → resource.img处理
第5858行: DTB: rk-kernel.dtb → 从resource读取DTB
第5861行: [TaishanPi] Dynamic Device Tree Overlay Loader → overlay应用到此DTB ✓
第5925行: ## Booting FIT Image → FIT启动开始
第5943行: ## Loading fdt from FIT Image → 从FIT镜像加载全新DTB!
第5957行: Loading fdt from 0x78e79280 to 0x08300000 → 新DTB覆盖到0x08300000
第5958行: Booting using the fdt blob at 0x08300000 → 内核用的是这份新DTB!
关键问题:
overlay被应用到rockchip_read_dtb_file()处理的DTB上(来自resource.img),
但FIT启动过程从FIT镜像中提取了一份【全新的DTB】加载到0x08300000,
内核实际使用的是这份全新DTB,之前的overlay修改被完全覆盖。
时序图:
rockchip_read_dtb_file() → DTB_A (overlay applied) ← 被丢弃
↓
FIT boot → 加载 DTB_B (fresh, no overlay) to 0x08300000
↓
image_setup_libfdt(DTB_B) → fixup
↓
Kernel boots with DTB_B ← 没有overlay!
修复:
将overlay加载从boot_rkimg.c移到common/image-fdt.c的image_setup_libfdt()函数中。
image_setup_libfdt()处理的是FIT加载DTB之后、内核启动之前的【最终FDT】。
具体改动:
u-boot/arch/arm/mach-rockchip/boot_rkimg.c:
删除rockchip_load_dtbo_overlays()调用
删除extern声明
恢复原始的sysmem_alloc_base顺序(overlay不再在此处执行)
u-boot/common/image-fdt.c:
#include <asm/arch/overlay_loader.h> (CONFIG_OF_LIBFDT_OVERLAY && CONFIG_ARCH_ROCKCHIP)
在image_setup_libfdt()中fdt_fixup_ethernet()之后、fdt_shrink_to_minimum()之前
调用rockchip_load_dtbo_overlays(blob)用CONFIG_ARCH_ROCKCHIP保护,不影响其他平台
修正后时序:
rockchip_read_dtb_file() → DTB_A (no overlay)
↓
FIT boot → 加载 DTB_B (fresh) to 0x08300000
↓
image_setup_libfdt(DTB_B):
fdt_chosen()
fdt_fixup_ethernet()
rockchip_load_dtbo_overlays(DTB_B) ← overlay应用到最终DTB ✓
fdt_shrink_to_minimum()
↓
Kernel boots with DTB_B (with overlay) ← 生效!
【最终文件变更清单】
---- U-Boot ----
[新增] u-boot/arch/arm/mach-rockchip/overlay_loader.c
[新增] u-boot/arch/arm/include/asm/arch-rockchip/overlay_loader.h
[修改] u-boot/arch/arm/mach-rockchip/Makefile
+ obj-$(CONFIG_OF_LIBFDT_OVERLAY) += overlay_loader.o
[修改] u-boot/configs/rk3568_defconfig
+ CONFIG_OF_LIBFDT_OVERLAY=y
+ CONFIG_DISTRO_DEFAULTS=y
~ CONFIG_BOOTDELAY=2
[修改] u-boot/common/image-fdt.c
+ #include <asm/arch/overlay_loader.h>
+ rockchip_load_dtbo_overlays(blob) in image_setup_libfdt()
[未改] u-boot/arch/arm/mach-rockchip/boot_rkimg.c
(恢复原始状态,overlay调用已移至image-fdt.c)
---- Kernel ----
[新增] kernel-6.1/arch/arm64/boot/dts/rockchip/device-tree-overlays/Makefile
[新增] kernel-6.1/arch/arm64/boot/dts/rockchip/device-tree-overlays/ubootEnv.txt
[新增] kernel-6.1/arch/arm64/boot/dts/rockchip/device-tree-overlays/overlays/leds-test.dts
---- SDK构建系统 ----
[修改] device/rockchip/common/scripts/mk-kernel.sh
+ overlay编译和复制逻辑
[新增] device/rockchip/common/post-hooks/92-overlays.sh
安装overlay到rootfs /boot
【验证方法】
编译: ./build.sh all (或分步: ./build.sh uboot && ./build.sh kernel && ./build.sh buildroot)
烧录固件
设备上编辑 /boot/ubootEnv.txt:
overlays=leds-test.dtbosync && reboot
串口确认:
[TaishanPi] Dynamic Device Tree Overlay Loader
[leds-test.dtbo] Applied successfully
Summary: Applied 1 of 1 overlay(s)硬件验证: 三色LED应停止闪烁 (status="disabled"生效)
禁用验证: 注释掉overlays=行,重启后LED恢复闪烁
【自定义Overlay编写指南】
在 kernel-6.1/arch/arm64/boot/dts/rockchip/device-tree-overlays/overlays/ 下
新建 .dts 文件:
/dts-v1/;
/plugin/;
/ {
fragment@0 {
target = <&节点标签>;
__overlay__ {
属性 = 值;
};
};
};
支持#include预处理 (由Makefile的CPP步骤处理)。
编译: ./build.sh kernel
节点标签必须在主设备树中存在,否则报FDT_ERR_NOTFOUND。


评论