2. 设备树语法入门

设备树(Device Tree,DT)是一种描述硬件拓扑和资源分配的数据结构,它使用树形节点和键值对属性来描述硬件设备。本章将系统讲解设备树源文件(.dts)的核心语法要素:节点(node)、属性(property)、标签(label)和别名(aliases)。

学习提示:设备树语法是驱动开发的基础,掌握节点与属性的关系后,才能正确编写和修改设备树文件。建议边学边在开发板上验证。

2.1 节点(Node)—— 设备树的骨架

节点是设备树的基本组成单元,每个节点代表一个硬件设备、总线或功能模块。节点从根节点(/)开始,形成树形层级结构。

2.1.1 节点定义语法

/dts-v1/;

/ {
    node1 {
        child-node {
            /* 子节点内容 */
        };
    };
    node2 {
        /* 节点内容 */
    };
};
  • 根节点:用 / 表示,是整个设备树的起点。
  • 子节点:在父节点的大括号内定义,节点名通常反映设备类型或实例。
  • 节点结束:每个节点必须以分号 ; 结尾。

2.1.2 节点名称规范

格式 示例 说明
node-name cpu 通用节点名,不包含地址
node-name@unit-address uart@fe001000 包含寄存器或总线地址,用于区分同类型设备
node-name: label uart0: serial@fe001000 带标签的节点,便于在其他位置引用
关键规则:当同一层级存在多个同类型设备时,必须使用 @unit-address 形式来区分地址,否则编译器会报重复节点错误。
设备树节点层级结构 根节点 / soc chosen uart@fe001000 i2c@fe002000 rtc@68 节点层级说明 根节点 → 总线节点 → 外设节点 每个节点可包含子节点 @unit-address 区分同类型设备

2.2 属性(Property)—— 描述设备特征

属性是附加在节点上的键值对,用于描述设备的硬件特征、寄存器地址、中断号、时钟频率等信息。属性值可以是空、整数、字符串、字节数组或这些类型的组合。

2.2.1 常用属性类型

属性类型 语法格式 示例 说明
空属性 property-name; disable; 仅表示存在,无值
32位整数 property-name = <value>; reg = <0xfe001000 0x1000>; 尖括号内可包含多个整数
64位整数 property-name = <0x00000000 0x80000000>; reg = <0x00000000 0x80000000>; 用两个32位整数拼接
字符串 property-name = "string"; compatible = "snps,dw-apb-uart"; 双引号包裹
字节数组 property-name = [hex-bytes]; local-mac-address = [00 11 22 33 44 55]; 十六进制字节序列
字符串列表 property-name = "str1", "str2"; compatible = "ti,am335x-uart", "ns16550"; 逗号分隔多个字符串

2.2.2 标准属性详解

设备树规范定义了一组标准属性,驱动开发者必须熟悉:

  • compatible:设备兼容性字符串,驱动匹配的核心依据。格式为 "厂商,设备型号"。
  • reg:描述设备地址空间,格式为 <地址 长度> 对。
  • interrupts:描述中断号、触发类型等信息。
  • status:设备状态,可选 okay、disabled、fail 等。
  • clocks:引用时钟控制器和时钟索引。
uart0: serial@fe001000 {
    compatible = "snps,dw-apb-uart";
    reg = <0xfe001000 0x1000>;
    interrupts = <0 33 4>;
    clocks = <&uart_clk>;
    status = "okay";
};
常见错误:忘记在属性值末尾加分号 ;,或字符串未使用双引号包裹,会导致设备树编译失败。

2.3 标签(Label)—— 节点的引用标识

标签是附加在节点名称前的标识符,用于在其他位置引用该节点。标签在设备树覆盖(overlay)和跨文件引用中至关重要。

2.3.1 标签定义语法

标签名: 节点名@地址 {
    /* 节点内容 */
};

示例:

uart1: serial@fe002000 {
    compatible = "snps,dw-apb-uart";
    reg = <0xfe002000 0x1000>;
};

2.3.2 标签引用方式

引用语法 示例 说明
&label &uart1 在属性值或覆盖文件中引用节点
phandle = <&label> clocks = <&uart_clk>; 在属性中引用其他节点
&label { ... }; &uart1 { status = "disabled"; }; 在覆盖文件中修改节点属性
最佳实践:为所有可能被覆盖或引用的节点添加标签,标签名应具有描述性,如 uart0、i2c1、mmc0。
标签引用与覆盖关系 基础设备树 (base.dts) uart0: serial@fe001000 i2c0: i2c@fe002000 标签: uart0, i2c0 覆盖文件 (overlay.dts) &uart0 { status = "okay"; } &i2c0 { clock-frequency = <100000>; } 通过 &label 引用基础节点 编译后设备树 uart0 状态改为 okay,i2c0 频率设为 100kHz 标签作用 1. 提供稳定的引用标识 2. 支持设备树覆盖修改

2.4 别名(Aliases)—— 简化路径引用

别名是定义在根节点 aliases 子节点中的快捷路径映射,用于简化对深层节点的引用。别名在 U-Boot 和内核启动参数中广泛使用。

2.4.1 别名定义语法

/ {
    aliases {
        serial0 = &uart0;
        serial1 = &uart1;
        i2c0 = &i2c0;
        mmc0 = &mmc0;
    };
};

2.4.2 别名使用场景

场景 示例 说明
U-Boot 环境变量 setenv bootargs console=ttyS0,115200 通过别名 serial0 映射到实际串口节点
内核启动参数 console=ttyAMA0 内核根据别名查找对应设备节点
设备树覆盖 &mmc0 { status = "okay"; }; 通过别名引用节点,避免写完整路径
用户空间访问 /sys/firmware/devicetree/base/aliases/serial0 用户态程序可通过别名路径访问设备树信息

2.4.3 别名与标签的区别

对比项 标签(Label) 别名(Aliases)
定义位置 节点定义处 根节点下的 aliases 子节点
引用方式 &label aliases 中的字符串映射
主要用途 设备树内部引用和覆盖 外部工具和启动参数引用
编译后存在 转换为 phandle 属性 保留为 aliases 节点中的属性
可读性 适合开发者 适合脚本和用户空间
/* 完整示例:标签与别名配合使用 */
/ {
    aliases {
        serial0 = &uart0;
        serial1 = &uart1;
    };

    soc {
        uart0: serial@fe001000 {
            compatible = "snps,dw-apb-uart";
            reg = <0xfe001000 0x1000>;
            interrupts = <0 33 4>;
            status = "okay";
        };

        uart1: serial@fe002000 {
            compatible = "snps,dw-apb-uart";
            reg = <0xfe002000 0x1000>;
            interrupts = <0 34 4>;
            status = "disabled";
        };
    };
};
实用技巧:在编写设备树时,建议为所有可能被外部引用的设备(串口、I2C、SPI、MMC、以太网)定义别名。别名命名应遵循 设备类型+序号 的规范,如 serial0、i2c1、mmc0。

2.5 综合示例:完整的设备树片段

以下示例综合展示了节点、属性、标签和别名的实际应用:

/dts-v1/;

/ {
    model = "Embedded Linux Development Board";
    compatible = "vendor,board-rev1";

    aliases {
        serial0 = &uart0;
        serial1 = &uart1;
        i2c0 = &i2c0;
        mmc0 = &mmc0;
    };

    chosen {
        stdout-path = &uart0;
        bootargs = "console=ttyS0,115200 root=/dev/mmcblk0p2";
    };

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

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

        uart0: serial@fe001000 {
            compatible = "snps,dw-apb-uart";
            reg = <0xfe001000 0x1000>;
            interrupts = <0 33 4>;
            clocks = <&uart_clk>;
            status = "okay";
        };

        uart1: serial@fe002000 {
            compatible = "snps,dw-apb-uart";
            reg = <0xfe002000 0x1000>;
            interrupts = <0 34 4>;
            clocks = <&uart_clk>;
            status = "disabled";
        };

        i2c0: i2c@fe003000 {
            compatible = "snps,designware-i2c";
            reg = <0xfe003000 0x1000>;
            interrupts = <0 35 4>;
            clocks = <&i2c_clk>;
            #address-cells = <1>;
            #size-cells = <0>;
            status = "okay";

            rtc@68 {
                compatible = "dallas,ds1307";
                reg = <0x68>;
            };
        };

        mmc0: mmc@fe004000 {
            compatible = "snps,dw-mshc";
            reg = <0xfe004000 0x1000>;
            interrupts = <0 36 4>;
            clocks = <&mmc_clk>;
            status = "okay";
        };
    };

    uart_clk: clock {
        compatible = "fixed-clock";
        #clock-cells = <0>;
        clock-frequency = <24000000>;
    };

    i2c_clk: clock {
        compatible = "fixed-clock";
        #clock-cells = <0>;
        clock-frequency = <50000000>;
    };

    mmc_clk: clock {
        compatible = "fixed-clock";
        #clock-cells = <0>;
        clock-frequency = <100000000>;
    };
};
要点总结:
  • 节点构成设备树的层级骨架,@unit-address 用于区分同类型设备。
  • 属性以键值对形式描述设备特征,compatible 是驱动匹配的核心。
  • 标签提供稳定的节点引用标识,支持设备树覆盖和跨文件引用。
  • 别名定义在 aliases 节点中,为外部工具和启动参数提供快捷路径。
  • 所有语句必须以分号 ; 结尾,注释使用 /* */ 或 //。
设备树语法要素关系 设备树 (DT) 节点 (Node) 属性 (Property) 标签 (Label) 别名 (Aliases) 硬件设备层级 设备特征描述 节点引用标识 快捷路径映射

2.6 本章小结

设备树语法是嵌入式 Linux 驱动开发的基石。节点定义了硬件拓扑,属性描述了设备细节,标签提供了灵活的引用机制,别名则简化了外部访问路径。掌握这四大要素后,开发者能够阅读和编写标准的设备树源文件,为后续的设备树覆盖和动态配置打下坚实基础。