第4章 RK3568设备树文件结构:dts、dtsi、dtb文件关系与内核编译流程
设备树这玩意儿,刚接触的时候很容易被一堆后缀名搞晕。.dts、.dtsi、.dtb,还有编译时冒出来的.dtb.o,到底谁是谁?
我当年第一次移植内核,对着这些文件愣了半天。后来踩了几个坑,才算真正理清了它们的关系。今天咱们就把这层窗户纸捅破。
4.1 三种文件类型:源码、头文件、二进制
说白了,设备树的文件体系跟C语言非常像。你写C代码有.c源文件、.h头文件,编译出来是.o或者可执行文件。设备树也一样:
| 文件后缀 | 类比C语言 | 作用 | 是否可读 |
|---|---|---|---|
| .dts | .c 源文件 | 具体板卡的设备树源文件,描述整块板子的硬件 | 是(文本) |
| .dtsi | .h 头文件 | 公共的设备树包含文件,放SoC通用定义、IP核模板 | 是(文本) |
| .dtb | .o / 可执行文件 | 编译后的二进制设备树,内核启动时直接解析 | 否(二进制) |
核心记忆点: .dtsi 是“芯片级”的,.dts 是“板级”的。一个SoC对应一个.dtsi,但可以衍生出几十个不同板卡的.dts。
4.2 从.dts到.dtb:编译流程拆解
内核编译设备树的入口,一般在 arch/arm64/boot/dts/rockchip/ 目录下。你执行 make dtbs 的时候,背后发生了什么?
我习惯把流程分成三步:
- 预处理:C预处理器(cpp)登场。它处理
#include、#define、#ifdef这些指令。把.dtsi文件展开,把宏替换掉。这一步输出一个纯正的、没有包含关系的.dts文件。 - 编译:设备树编译器(dtc)上场。它把预处理后的.dts解析成抽象语法树,检查语法错误,然后生成.dtb二进制文件。
- 打包(可选):有些场景会把多个.dtb打包成一个文件(比如FIT image),但RK3568标准启动流程里,每个.dtb是独立的。
一个小技巧: 如果你想看预处理后的完整.dts长什么样,可以用 make ARCH=arm64 rockchip/rk3568-evb1-v10.dtb 编译,然后在同目录下找 *.dtb.d.pre.tmp 文件。那里就是展开后的源码,调试节点覆盖问题特别好用。
4.3 包含关系与覆盖规则
RK3568的设备树文件,层级关系非常清晰。我画了一张图,你看一眼就明白了:
你看,rk3568.dtsi 定义了CPU、GIC、定时器这些SoC内部模块。而 rk3568-evb1-v10.dts 通过 #include "rk3568.dtsi" 把它拉进来,再补充DDR容量、网卡型号、GPIO复用这些板级信息。
我曾经踩过一个坑: 在.dts里重新定义了.dtsi中已经存在的节点,但忘了检查 status = "okay"。结果内核启动时,那个外设死活不工作。后来才发现,覆盖节点时如果只改属性不改status,默认是 disabled 的。记住:覆盖节点时,status 属性必须显式设置。
4.4 内核编译流程中的设备树
在RK3568的Linux内核里,设备树的编译是跟内核镜像编译解耦的。你编译内核时,可以选择只编译设备树:
# 编译内核镜像 + 所有设备树
make ARCH=arm64 rockchip_defconfig
make ARCH=arm64 -j8
# 只编译设备树
make ARCH=arm64 dtbs
# 编译指定板卡的设备树
make ARCH=arm64 rockchip/rk3568-evb1-v10.dtb
编译完成后,.dtb文件会出现在 arch/arm64/boot/dts/rockchip/ 目录下。你把它跟内核镜像、根文件系统一起打包,就能启动系统了。
嗯,这里要注意一个细节:设备树编译的依赖关系。如果你改了 rk3568.dtsi,所有包含它的.dts都需要重新编译。内核的Makefile会自动处理这个依赖,但如果你手动拷贝.dtb文件,很容易忘记重新编译。
我的习惯: 每次修改设备树后,都执行一次 make dtbs,确保所有相关.dtb都是最新的。然后检查git diff,确认改动确实生效了。
4.5 反编译:从.dtb回到.dts
有时候你拿到一个别人的.dtb,或者想确认编译结果对不对,可以用dtc反编译:
# 反编译 .dtb 为 .dts
dtc -I dtb -O dts -o output.dts rk3568-evb1-v10.dtb
# 常用参数说明
# -I dtb : 输入格式是dtb
# -O dts : 输出格式是dts
# -o : 指定输出文件名
反编译出来的.dts,节点顺序可能跟源码不一样,但内容是完全等价的。我调试节点覆盖问题时,经常用这个命令来验证最终效果。
4.6 本章小结
| 概念 | 一句话总结 |
|---|---|
| .dtsi | SoC级公共定义,类似C头文件 |
| .dts | 板级具体实现,包含并覆盖.dtsi |
| .dtb | 编译后的二进制,内核直接使用 |
| 编译流程 | 预处理 → dtc编译 → 生成.dtb |
| 反编译 | dtc -I dtb -O dts,调试利器 |
设备树的文件结构,说白了就是“分层复用,板级定制”。理解了这个思路,后面看任何芯片的设备树,你都能快速找到关键节点。