1、设备树基础:什么是设备树?为什么需要设备树?设备树的历史与演进
1.1 什么是设备树?
设备树,英文叫 Device Tree,是一套用来描述硬件的数据结构。
说白了,它就是一份「硬件配置清单」。你想想看,一块电路板上有什么?CPU、内存、I2C控制器、SPI控制器、GPIO、中断控制器……这些东西怎么连接的?地址是多少?中断号是多少?设备树就是把这些信息用树形结构写出来。
我习惯把设备树比作「硬件的身份证」。内核启动时,不再需要去猜硬件长什么样,直接读设备树就行。
设备树的文件后缀通常是 .dts(Device Tree Source),编译后变成 .dtb(Device Tree Blob),内核在启动时加载它。
核心要点:设备树是描述硬件的结构化数据,不是代码,不执行逻辑,只提供信息。
1.2 为什么需要设备树?
这个问题,得从 Linux 内核的历史说起。
早期的 Linux 内核,硬件信息是硬编码在 C 代码里的。比如你要支持一块开发板,就得在 arch/arm/mach-xxx 目录下写一堆板级文件。每个板子一个文件,里面全是 platform_device、resource、i2c_board_info 这些东西。
我在项目中遇到过这种情况:公司同时维护 5 款硬件,每款硬件又有 3 个变种。结果内核源码里塞了 15 套板级文件。每次改一个 GPIO,得改 15 个地方。改完还要重新编译整个内核。你说崩溃不崩溃?
设备树解决了三个核心痛点:
- 硬件与驱动解耦:驱动不再关心硬件具体怎么接的,只关心设备树里有什么属性。
- 减少内核代码量:板级文件从内核源码里移出去,变成设备树文件,单独维护。
- 支持多平台启动:同一个内核镜像,换一个
.dtb文件就能适配不同硬件。
我的经验:有一次客户临时改板子,把 UART2 的引脚换到了 UART1 的位置。我只需要改设备树里的引脚复用配置,重新编译 .dtb,内核都不用动。这在以前,得改板级文件、重新编译内核、再烧录。效率差距太大了。
1.3 设备树的历史与演进
设备树最早不是 Linux 的发明。它来自 Open Firmware,一种用于 PowerPC 和 SPARC 架构的固件标准。Open Firmware 用设备树来描述硬件,然后传递给操作系统。
Linux 内核在 PowerPC 架构上最早用上了设备树。后来 ARM 架构也面临板级文件泛滥的问题,社区开始讨论要不要引入设备树。
我记得大概是 2011 年左右,Linux 3.x 时代,ARM 社区正式决定全面转向设备树。当时 Linus Torvalds 也发过火,说 ARM 的板级文件太乱了,必须统一。
演进过程大致是这样的:
| 时间 | 阶段 | 说明 |
|---|---|---|
| 2005 年以前 | PowerPC 使用 | 设备树在 PowerPC 架构上成熟应用 |
| 2011-2012 年 | ARM 引入 | Linux 3.2 开始支持 ARM 设备树 |
| 2013-2015 年 | 全面推广 | 新 ARM 平台强制使用设备树,板级文件逐步废弃 |
| 2016 年至今 | 标准化与扩展 | 设备树规范持续更新,支持更多外设和绑定 |
现在,不只是 ARM,RISC-V、X86(部分场景)、MIPS 等架构也在用设备树。它已经成为 Linux 内核描述硬件的标准方式。
注意:设备树不是万能的。它只描述「静态硬件」,像 USB 热插拔、PCIe 枚举这类动态硬件,设备树管不了。那些需要 ACPI 或者驱动自己去探测。
1.4 设备树的基本结构
一个最简单的设备树长什么样?我写个例子给你看:
/dts-v1/;
/ {
model = "MyBoard";
compatible = "vendor,myboard-v1";
#address-cells = <1>;
#size-cells = <1>;
memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x10000000>;
};
uart@10000000 {
compatible = "ns16550";
reg = <0x10000000 0x1000>;
interrupts = <0 33 4>;
};
};
这里有几个关键概念:
- 根节点:
/表示整棵树的根,相当于电路板本身。 - 节点:
memory、uart都是节点,代表一个硬件设备。 - 属性:
compatible、reg、interrupts都是属性,描述设备的特征。 - 地址与大小:
#address-cells和#size-cells告诉解析器地址和长度用几个 32 位整数表示。
嗯,这里要注意:compatible 属性是驱动匹配的关键。内核通过它找到对应的驱动程序。命名规则一般是「厂商,设备型号」。
一句话总结:设备树就是硬件的「自我介绍」。内核启动时问它:「你是谁?你有哪些资源?你的中断号是多少?」设备树一一回答。没有设备树,内核就是个瞎子。
我个人觉得,理解设备树最好的方式就是动手写一个。别怕,后面几章我会带你一步步从零开始写设备树,还会结合 Regmap 和 MMIO 讲清楚怎么配置硬件寄存器。到时候你就知道,设备树这东西,其实没那么玄乎。