联系管理员

开通文章发布权限

扫码 添加微信
微信图片
电话: QQ:1602036736

实现动态设备树


RK3566 Buildroot 动态设备树加载功能 - 完整调试日志
平台: TaishanPi RK3566 | Kernel 6.1 | Linux SDK
日期: 2026-03-25


参考文档:


【第一阶段】初始实现 - 移植RK3576补丁到RK3566


补丁来源: LinuxSDK动态设备树插件补丁_20251224.zip (基于RK3576)

---- 新增文件 ----

  1. 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),不使用栈

  2. u-boot/arch/arm/include/asm/arch-rockchip/overlay_loader.h [新增]

    • 头文件,声明 rockchip_load_dtbo_overlays(void *fdt_addr)

  3. kernel-6.1/arch/arm64/boot/dts/rockchip/device-tree-overlays/Makefile [新增]

    • overlay编译系统,两步编译:CPP预处理 + DTC编译

    • 支持#include语法

  4. kernel-6.1/arch/arm64/boot/dts/rockchip/device-tree-overlays/ubootEnv.txt [新增]

    • 用户配置模板,overlays=行指定要加载的dtbo文件

  5. kernel-6.1/arch/arm64/boot/dts/rockchip/device-tree-overlays/overlays/leds-test.dts [新增]

    • 示例overlay

  6. device/rockchip/common/post-hooks/92-overlays.sh [新增]

    • rootfs打包时将ubootEnv.txt和*.dtbo安装到/boot

---- 修改文件 ----

  1. u-boot/arch/arm/mach-rockchip/Makefile [修改]

    • obj-$(CONFIG_OF_LIBFDT_OVERLAY) += overlay_loader.o

  2. u-boot/arch/arm/mach-rockchip/boot_rkimg.c [修改]

    • extern声明 rockchip_load_dtbo_overlays

    • 在rockchip_read_dtb_file()末尾调用 rockchip_load_dtbo_overlays()

  3. u-boot/configs/rk3568_defconfig [修改]

    • CONFIG_OF_LIBFDT_OVERLAY=y (启用FDT overlay支持)

    • CONFIG_DISTRO_DEFAULTS=y (启用distro默认配置,含fs支持)
      ~ CONFIG_BOOTDELAY=0 → 2 (留出U-Boot交互时间)

  4. 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),但紧接着:

## Booting FIT Image Sysmem Error: Failed to double alloc for existence "FDT"

系统无法启动,进入错误恢复循环。

根因分析:
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】。

具体改动:

  1. u-boot/arch/arm/mach-rockchip/boot_rkimg.c:

    • 删除rockchip_load_dtbo_overlays()调用

    • 删除extern声明

    • 恢复原始的sysmem_alloc_base顺序(overlay不再在此处执行)

  2. 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


【验证方法】

 

  1. 编译: ./build.sh all (或分步: ./build.sh uboot && ./build.sh kernel && ./build.sh buildroot)

  2. 烧录固件

  3. 设备上编辑 /boot/ubootEnv.txt:
    overlays=leds-test.dtbo

  4. sync && reboot

  5. 串口确认:
    [TaishanPi] Dynamic Device Tree Overlay Loader
    [leds-test.dtbo] Applied successfully
    Summary: Applied 1 of 1 overlay(s)

  6. 硬件验证: 三色LED应停止闪烁 (status="disabled"生效)

  7. 禁用验证: 注释掉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。


评论

快捷导航

把好文章收藏到微信

打开微信,扫码查看

关闭

还没有账号?立即注册