3. 设备树(Device Tree)基础:设备树的作用、dts/dtsi/dtb文件格式、节点与属性

3.1 设备树的作用

设备树(Device Tree,DT)是一种描述硬件资源的数据结构,用于将硬件配置信息从Linux内核源码中分离出来。在嵌入式Linux系统中,设备树是驱动开发者与硬件平台之间的“硬件配置契约”。

核心作用: 设备树将“硬件是什么”与“驱动怎么用”解耦,使得同一份内核镜像可以支持多种硬件平台,无需重新编译内核。

设备树的主要作用包括:

  • 硬件描述: 描述CPU、内存、外设(I2C、SPI、UART、GPIO、中断控制器等)的地址、中断、时钟、复位等资源。
  • 驱动匹配: 提供 compatible 属性,供内核驱动通过 of_match_table 进行设备与驱动的匹配。
  • 资源传递: 驱动通过设备树API(如 of_property_read_u32、irq_of_parse_and_map)获取硬件配置参数,避免硬编码。
  • 平台无关化: 同一份内核镜像,通过更换不同的设备树文件(.dtb),即可适配不同硬件板卡。
设备树在驱动开发中的角色 硬件板卡 CPU / 内存 / 外设 设备树源文件 .dts / .dtsi Linux内核驱动 匹配 / 解析 / 使用 描述硬件 提供配置 设备树解耦流程 硬件板卡 → 编写 .dts → 编译为 .dtb → Bootloader加载 → 内核解析 → 驱动匹配 → 驱动通过API读取硬件资源

3.2 dts / dtsi / dtb 文件格式

设备树涉及三种主要文件格式,它们在开发流程中扮演不同角色:

文件后缀 全称 作用 是否可编译 典型用途
.dts Device Tree Source 设备树源文件,描述一个具体板卡的硬件 是(→ .dtb) 板级硬件描述,如 imx6ull-evk.dts
.dtsi Device Tree Source Include 设备树头文件/包含文件,可被 .dts 或其它 .dtsi 包含 否(仅被包含) SoC 公共定义、IP 核模板,如 imx6ull.dtsi
.dtb Device Tree Blob 设备树二进制文件,由 .dts 编译生成,供 Bootloader 加载 否(已编译) 内核启动时由 Bootloader 传递给内核
开发习惯: 将 SoC 公共部分(如 CPU、中断控制器、时钟)放在 .dtsi 中,板级差异(如 GPIO 按键、LED、外设地址)放在 .dts 中。通过 #include 机制复用,避免重复定义。

编译流程:

# 将 .dts 编译为 .dtb
dtc -I dts -O dtb -o myboard.dtb myboard.dts

# 反编译 .dtb 为 .dts(调试用)
dtc -I dtb -O dts -o myboard_decompiled.dts myboard.dtb
dts / dtsi / dtb 编译与加载流程 .dtsi SoC公共定义 .dts 板级硬件描述 dtc 编译器 Device Tree Compiler .dtb 二进制文件 #include Bootloader(U-Boot)加载 .dtb 传递给 Linux 内核

3.3 节点与属性

设备树的核心语法由 节点(Node) 和 属性(Property) 组成,采用树形层级结构描述硬件拓扑。

3.3.1 节点(Node)

节点是设备树的基本单元,每个节点代表一个硬件设备或总线。节点名称格式为 node-name@unit-address,其中 unit-address 通常为设备基地址。

/ {
    #address-cells = <1>;
    #size-cells = <1>;

    soc {
        compatible = "simple-bus";
        #address-cells = <1>;
        #size-cells = <1>;
        ranges;

        gpio0: gpio@2090000 {
            compatible = "fsl,imx6ul-gpio", "fsl,imx35-gpio";
            reg = <0x02090000 0x4000>;
            interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>;
            gpio-controller;
            #gpio-cells = <2>;
        };
    };
};

节点关键概念:

  • 根节点: / 是设备树的根,所有设备节点都是根节点的子节点。
  • 标签(Label): 如 gpio0:,用于在其它地方引用该节点(通过 &gpio0)。
  • 节点路径: 如 /soc/gpio@2090000,唯一标识一个节点。
  • 子节点: 节点可以嵌套,形成树形结构。

3.3.2 属性(Property)

属性是节点的键值对,用于描述设备的配置信息。常见属性类型如下:

属性名 类型 说明 示例
compatible 字符串列表 驱动匹配标识,格式为 "厂商,型号" "fsl,imx6ul-gpio"
reg u32/u64 数组 设备地址范围,格式为 (地址, 长度) 对 <0x02090000 0x4000>
interrupts u32 数组 中断描述,格式依赖中断控制器 <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>
interrupt-parent phandle 指定该设备连接的中断控制器 &intc
gpio-controller 空属性 标记该节点为 GPIO 控制器 无值
#gpio-cells u32 GPIO 描述符需要的 cell 数量 <2>
status 字符串 设备状态:"okay" / "disabled" "okay"
clock-frequency u32 时钟频率(Hz) <24000000>
注意: #address-cells 和 #size-cells 决定 reg 属性中地址和长度的 cell 数量。例如 #address-cells = <1> 表示地址占 1 个 u32(32位),#size-cells = <1> 表示长度占 1 个 u32。对于 64 位地址空间,应设置为 <2>。

3.3.3 节点与属性的树形结构

设备树节点与属性结构示例 / (根节点) #address-cells = <1> #size-cells = <1> soc compatible = "simple-bus" ranges; gpio0: gpio@2090000 标签: gpio0 compatible = "fsl,imx6ul-gpio" reg = <0x02090000 0x4000> interrupts = <GIC_SPI 66 ...> key@0 子节点 compatible = "gpio-keys" gpios = <&gpio0 3 0> linux,code = <KEY_ENTER> 节点通过标签(如 gpio0)被引用:gpios = <&gpio0 3 0> 表示使用 gpio0 的第3号引脚

3.4 设备树中的中断描述

中断是设备树中最重要的资源之一。设备树通过 interrupts、interrupt-parent、interrupt-controller 等属性描述中断拓扑。

中断相关属性:

属性 作用 示例
interrupt-controller 空属性,标记该节点为中断控制器 interrupt-controller;
#interrupt-cells 指定中断描述符需要的 cell 数量 #interrupt-cells = <3>(GIC 格式)
interrupt-parent 指定该设备连接的中断控制器 phandle interrupt-parent = &intc;
interrupts 中断号、触发类型等描述 interrupts = <0 66 4>
GIC 中断 cell 格式(ARM 通用):
<中断类型 中断号 触发类型>
  • 中断类型: 0 = SPI(共享外设中断),1 = PPI(私有外设中断)
  • 中断号: SPI 从 32 开始编号,如 SPI 66 表示中断号 66
  • 触发类型: 1 = 上升沿触发,4 = 高电平触发

3.5 设备树在驱动中的使用流程

驱动开发者通过设备树 API 获取硬件配置,典型流程如下:

  1. 编写设备树节点: 在 .dts 中定义设备节点,填写 compatible、reg、interrupts 等属性。
  2. 编译设备树: 使用 dtc 将 .dts 编译为 .dtb。
  3. 驱动匹配: 驱动通过 of_match_table 与设备树节点的 compatible 属性匹配。
  4. 资源解析: 驱动使用 of_property_read_u32、irq_of_parse_and_map、of_iomap 等 API 读取设备树中的配置。
  5. 硬件操作: 驱动根据解析到的地址、中断号、GPIO 号等参数初始化硬件。
调试技巧: 在 Linux 内核启动后,可以通过 /proc/device-tree 查看当前使用的设备树内容。使用 dtc -I fs -O dts /proc/device-tree 可以导出当前设备树的 .dts 格式。

设备树是嵌入式 Linux 驱动开发的基石,掌握节点、属性、中断描述和编译流程,是后续学习中断申请与属性解析的前提。