1. 设备树基础概念
1.1 什么是设备树(Device Tree)
设备树(Device Tree,DT)是一种描述硬件资源的数据结构,它使用树形节点来记录系统中所有可访问的设备、总线、中断控制器、时钟、GPIO 等硬件信息。设备树源文件(.dts)经过编译生成设备树二进制文件(.dtb),由 Bootloader 传递给内核,内核解析后自动完成设备驱动与硬件资源的绑定。
核心定义:设备树 = 硬件拓扑的静态描述语言 + 内核驱动匹配的桥梁。
一个典型的设备树节点结构如下:
/dts-v1/;
/ {
model = "TI AM335x BeagleBone Black";
compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
compatible = "arm,cortex-a8";
reg = <0x0>;
};
};
memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x20000000>; /* 512 MB */
};
uart0: serial@44e09000 {
compatible = "ti,am3352-uart", "ti,omap3-uart";
reg = <0x44e09000 0x2000>;
interrupts = <72>;
status = "okay";
};
};
关键字段说明:
compatible — 驱动匹配的核心字符串,格式为 "厂商,型号";
reg — 地址/长度对,描述设备占用的物理地址空间;
interrupts — 中断号,依赖父级中断控制器解析。
compatible — 驱动匹配的核心字符串,格式为 "厂商,型号";
reg — 地址/长度对,描述设备占用的物理地址空间;
interrupts — 中断号,依赖父级中断控制器解析。
1.2 为什么需要设备树
在设备树出现之前,嵌入式 Linux 内核使用 板级文件(Board File) 来注册硬件信息。每个开发板都需要在 arch/arm/mach-xxx 下编写大量 C 代码,导致内核源码中充斥着平台相关的硬编码。这种模式存在三个严重问题:
- 代码膨胀 — 每个新板子都要新增或修改板级文件,内核主线难以维护。
- 耦合过高 — 硬件描述与驱动代码深度绑定,更换 SoC 或外设需要重新编译内核。
- 碎片化严重 — 厂商各自维护分支,社区无法统一推进新特性。
设备树将硬件描述从内核源码中剥离出来,形成独立的 .dts 文件,实现了以下关键改进:
| 对比维度 | 板级文件(旧) | 设备树(新) |
|---|---|---|
| 硬件描述位置 | 内核源码 arch/arm/mach-xxx |
独立 .dts 文件,与内核解耦 |
| 更换外设 | 修改 C 代码,重新编译内核 | 修改 .dts,重新编译 DTB |
| 多板支持 | 每个板子一个板级文件 | 通过 #include 和 .dtsi 复用 |
| 驱动匹配方式 | 静态注册 platform_device | compatible 字符串动态匹配 |
| 社区维护成本 | 高(碎片化严重) | 低(统一描述语言) |
注意:设备树不是万能的。它只描述硬件“有什么”和“在哪里”,不描述硬件“怎么用”。驱动仍然需要实现具体的寄存器操作和中断处理逻辑。
1.3 设备树与 ACPI 的区别
ACPI(Advanced Configuration and Power Interface)是 x86 平台的标准硬件描述和电源管理接口,与设备树在理念和实现上有本质差异。两者对比如下:
| 对比维度 | 设备树(DT) | ACPI |
|---|---|---|
| 主要应用平台 | ARM、RISC-V、PowerPC 等嵌入式 | x86、x86_64(PC/服务器) |
| 描述语言 | DTS 文本格式,编译为二进制 DTB | ASL(ACPI Source Language),编译为 AML |
| 运行时行为 | 静态描述,内核解析后不再变化 | AML 解释执行,支持热插拔、电源事件 |
| 电源管理 | 依赖驱动实现,DT 只描述设备存在 | 内建 _PS0/_PS3 等电源状态控制方法 |
| 热插拔支持 | 有限,需额外驱动逻辑 | 原生支持 PCIe/USB 热插拔事件 |
| BIOS/UEFI 依赖 | 不需要,Bootloader 直接加载 DTB | 必须由 UEFI/BIOS 提供 ACPI 表 |
| 驱动匹配方式 | compatible 字符串 | HID(Hardware ID)/ CID(Compatible ID) |
| 社区生态 | Linux 内核主线 + 设备树邮件列表 | UEFI 论坛 + 微软/Intel 主导 |
核心差异总结:
设备树是“静态硬件清单”,适合资源受限、硬件固定的嵌入式系统;
ACPI 是“可编程硬件抽象层”,适合需要动态电源管理和热插拔的通用计算平台。
设备树是“静态硬件清单”,适合资源受限、硬件固定的嵌入式系统;
ACPI 是“可编程硬件抽象层”,适合需要动态电源管理和热插拔的通用计算平台。
1.4 设备树在嵌入式 Linux 中的位置
设备树是嵌入式 Linux 启动流程中的关键一环,位于 Bootloader 与内核之间:
- Bootloader(U-Boot) 从存储介质读取
.dtb文件。 - Bootloader 将 DTB 加载到内存,并通过寄存器(如
r2)传递地址给内核。 - 内核启动早期调用
unflatten_device_tree()将 DTB 展开为device_node树。 - 驱动通过
of_match_table匹配 compatible 字符串,获取reg、interrupts等资源。
实战建议:调试设备树问题时,优先检查
/sys/firmware/devicetree/base 下的节点内容,确认内核实际解析到的硬件信息是否与 .dts 一致。