1. 设备树概述:起源、作用与基本概念

1.1 为什么需要设备树?——从“硬编码”到“描述驱动”的演进

在早期的 Linux 内核中,板级硬件信息(如内存基地址、中断号、GPIO 映射、外设寄存器地址等)被直接硬编码在 arch/arm/mach-xxx 或 arch/powerpc/platforms/xxx 的 C 语言源文件中。这种“硬编码”方式带来了三个致命问题:

  • 代码膨胀:每增加一款开发板,内核就需要新增大量板级文件,导致内核源码体积急剧膨胀。
  • 维护灾难:不同厂商、不同 SoC 的板级代码混杂在一起,修改一处硬件配置可能影响多个平台。
  • 无法通用:同一份内核镜像无法同时支持多款硬件平台,必须为每块板子单独编译内核。
核心痛点:操作系统内核与硬件平台之间缺乏一个“标准化的硬件描述接口”。设备树(Device Tree)正是为了解决这一痛点而诞生的——它将硬件信息从内核代码中剥离出来,形成一份独立的数据结构,由 Bootloader 传递给内核。

1.2 设备树的起源与历史

时间 事件 影响
2005 年 PowerPC 架构率先引入设备树(Open Firmware 衍生) 解决了 PowerPC 平台板级代码混乱的问题
2008 年 ARM Linux 社区开始讨论引入设备树 ARM 平台板级文件数量已超过 3000 个,维护成本极高
2011 年 Linux 3.0 内核正式支持 ARM 设备树 ARM 平台开始逐步淘汰 mach-xxx 硬编码方式
2014 年 Linux 3.16 内核要求所有新 ARM 平台必须使用设备树 设备树成为 ARM 生态的强制标准
至今 RISC-V、x86(ACPI 替代场景)、MIPS 等架构也广泛采用 设备树已成为嵌入式 Linux 硬件描述的事实标准

1.3 设备树的核心作用

设备树在嵌入式系统中的角色可以概括为以下四点:

  1. 硬件描述标准化:使用树形结构描述 CPU、内存、总线、外设、中断控制器、GPIO 控制器等所有硬件资源。
  2. 内核与硬件解耦:同一份内核镜像通过加载不同的设备树文件(.dtb),即可适配不同的硬件平台。
  3. 驱动匹配依据:内核驱动通过设备树中的 compatible 属性与硬件节点进行匹配,实现“即插即用”。
  4. 配置灵活化:无需重新编译内核,仅修改设备树源文件(.dts)并重新编译生成 .dtb,即可调整硬件参数(如时钟频率、引脚复用、内存分区等)。
实战理解:设备树相当于一份“硬件说明书”,内核拿到这份说明书后,就知道如何初始化内存、如何配置中断、如何挂载驱动。没有设备树,内核就像“盲人摸象”,只能靠硬编码猜测硬件布局。

1.4 设备树的基本概念与文件体系

设备树涉及三个关键文件类型:

文件类型 扩展名 格式 作用
设备树源文件 .dts 文本(类似 C 语言结构体) 开发者编写硬件描述的源文件
设备树头文件 .dtsi 文本(可被 .dts 包含) SoC 级通用定义,可被多个板级 .dts 复用
设备树二进制文件 .dtb 二进制(扁平化) 由 .dts 编译生成,供 Bootloader 加载并传递给内核

一个典型的设备树节点结构如下:

/dts-v1/;

/ {
    model = "TI AM335x BeagleBone Black";
    compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";

    memory@80000000 {
        device_type = "memory";
        reg = <0x80000000 0x10000000>;  /* 512 MB RAM */
    };

    &uart0: serial@44e09000 {
        compatible = "ti,am3352-uart", "ns16550";
        reg = <0x44e09000 0x2000>;
        interrupts = <72>;
        status = "okay";
    };
};

1.5 设备树的工作流程(SVG 架构图)

设备树工作流程架构图 设备树工作流程:从 .dts 到内核驱动匹配 编写 .dts / .dtsi 硬件工程师/驱动开发者 dtc 编译 生成 .dtb 二进制 Bootloader 加载 U-Boot 传递 .dtb 给内核 内核 OF 子系统解析 .dtb 创建 device_node 树,注册 platform_device 驱动匹配与初始化 compatible 属性匹配 → probe() 执行 关键数据结构 • struct device_node • struct property • struct platform_device • struct of_device_id 匹配函数: of_match_table / of_match_node()

1.6 设备树 vs 传统硬编码:对比分析

对比维度 传统硬编码(mach-xxx) 设备树(Device Tree)
硬件描述位置 内核 C 源文件 独立 .dts 文本文件
平台适配方式 修改内核代码,重新编译 修改 .dts,重新编译 .dtb
多板支持 需要多份内核镜像 同一份内核 + 不同 .dtb
驱动匹配机制 platform_device 静态注册 compatible 属性动态匹配
维护成本 高(代码耦合严重) 低(硬件与驱动分离)
社区趋势 已被淘汰 ARM/RISC-V 强制标准
常见误区:设备树不是“驱动代码”,它只是硬件配置的“数据描述”。驱动仍然需要编写 C 代码,但驱动通过设备树获取硬件参数,而不是在代码中写死地址和中断号。初学者容易混淆“设备树配置”与“驱动逻辑”的边界。

1.7 本章小结

  • 设备树解决了嵌入式 Linux 中“硬件描述与内核代码耦合”的历史问题。
  • 它起源于 PowerPC,在 ARM 生态中成熟,现已成为 RISC-V 等新架构的标准。
  • 核心文件体系:.dts(源文件)→ dtc 编译 → .dtb(二进制)→ Bootloader 加载 → 内核解析。
  • 驱动通过 compatible 属性与设备树节点匹配,实现硬件与驱动的解耦。
  • 掌握设备树是嵌入式 Linux 驱动开发的必备技能,后续章节将深入节点、属性、中断、GPIO 等实战内容。