3. 设备树基础语法:DTS/DTC/DTB 概念、节点与属性
设备树(Device Tree)是嵌入式 Linux 中用于描述硬件拓扑结构的关键机制。在全志 T113 平台上,设备树文件决定了内核如何识别 CPU、内存、外设控制器以及 GPIO 引脚功能。本章将系统讲解设备树的核心概念、语法结构以及关键属性,为后续的 GPIO 驱动开发打下坚实基础。
学习目标:掌握 DTS → DTB 的编译流程;理解节点(node)与属性(property)的层级关系;熟练使用
#address-cells、#size-cells、reg、compatible 等核心属性。
3.1 DTS / DTC / DTB 概念与编译流程
设备树源文件(.dts)通过设备树编译器(DTC)编译为二进制设备树 blob(.dtb),U-Boot 或内核在启动时解析 DTB 以获取硬件信息。
| 文件类型 | 扩展名 | 格式 | 作用 |
|---|---|---|---|
| DTS | .dts | 文本(ASCII) | 设备树源文件,开发者编写硬件描述 |
| DTSI | .dtsi | 文本(ASCII) | 设备树包含文件,用于 SoC 级公共定义 |
| DTB | .dtb | 二进制 | 编译后的设备树,内核/U-Boot 直接使用 |
| DTC | — | 可执行程序 | 设备树编译器,将 DTS 转换为 DTB |
实战命令:在全志 T113 开发环境中,使用
dtc -I dts -O dtb -o sun8i-t113.dtb sun8i-t113.dts 完成编译;使用 dtc -I dtb -O dts -o decompiled.dts sun8i-t113.dtb 反编译验证。
3.2 节点(Node)与属性(Property)
设备树由树状结构的节点组成,每个节点代表一个硬件设备或总线,节点内包含若干属性来描述设备特征。
节点命名规则:节点名@单元地址,其中单元地址通常对应设备在总线上的起始地址。例如 uart0@1c28000 表示 UART0 控制器,其寄存器基地址为 0x01c28000。
属性类型:
- 字符串:
compatible = "allwinner,sun8i-t113-uart"; - 32 位整数:
reg = <0x01c28000 0x400>; - 64 位整数(双 32 位):
reg = <0x00000000 0x40000000 0x00000000 0x20000000>; - 布尔值:
status = "okay";或status = "disabled"; - 字节数组:
local-mac-address = [00 11 22 33 44 55];
3.3 #address-cells 与 #size-cells
这两个属性定义了 reg 属性中地址和长度字段的宽度(以 32 位字为单位)。
| 属性 | 取值 | 含义 |
|---|---|---|
#address-cells | 1 | 地址字段占 1 个 32 位字(32 位地址空间) |
#address-cells | 2 | 地址字段占 2 个 32 位字(64 位地址空间) |
#size-cells | 1 | 长度字段占 1 个 32 位字(最大 4GB 范围) |
#size-cells | 0 | 长度字段为空(仅表示地址,无范围) |
常见错误:在全志 T113 的
soc 节点中,#address-cells = <1> 且 #size-cells = <1>,因为 T113 的 32 位地址空间使用单字表示。如果错误设置为 2,会导致内核解析 reg 时读取错误的地址值,造成驱动无法匹配。
3.4 reg 属性
reg 属性描述设备的地址空间信息,格式为 reg = <地址1 长度1 地址2 长度2 ...>。每个地址-长度对称为一个 region,表示设备占用的连续地址范围。
// 全志 T113 UART0 节点示例
uart0: serial@1c28000 {
compatible = "allwinner,sun8i-t113-uart", "allwinner,sun6i-a31-uart";
reg = <0x01c28000 0x400>; // 基地址 0x01c28000,长度 0x400
interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&ccu CLK_BUS_UART0>;
status = "disabled";
};
// 多 region 示例(如 SPI 控制器带两个地址块)
spi0: spi@1c68000 {
compatible = "allwinner,sun8i-t113-spi";
reg = <0x01c68000 0x1000>, // 主寄存器块
<0x01c69000 0x100>; // 辅助 FIFO 块
#address-cells = <1>;
#size-cells = <0>;
};
全志 T113 关键外设 reg 地址速查:
- PIO(GPIO 控制器):
0x01c20800,长度0x400 - UART0:
0x01c28000,长度0x400 - I2C0:
0x01c2ac00,长度0x400 - SPI0:
0x01c68000,长度0x1000
3.5 compatible 属性
compatible 是设备树中最关键的属性之一,用于将设备节点与内核驱动进行匹配。其值为字符串列表,按优先级从高到低排列。
| 匹配方式 | 示例 | 说明 |
|---|---|---|
| 精确匹配 | "allwinner,sun8i-t113-uart" | 驱动中 of_match_table 完全匹配该字符串 |
| 兼容匹配 | "allwinner,sun6i-a31-uart" | 如果精确匹配失败,内核尝试兼容匹配(回退方案) |
| 通配匹配 | "simple-bus" | 用于总线节点,内核自动枚举子节点 |
// 全志 T113 GPIO 控制器节点(PIO)的 compatible 定义
pio: pinctrl@1c20800 {
compatible = "allwinner,sun8i-t113-pio";
reg = <0x01c20800 0x400>;
interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&ccu CLK_BUS_PIO>;
gpio-controller;
#gpio-cells = <3>;
interrupt-controller;
#interrupt-cells = <3>;
};
驱动匹配优先级:内核按照
of_match_table 中定义的顺序进行匹配。建议将最精确的 compatible 字符串放在最前面,通用兼容字符串放在后面。例如 "allwinner,sun8i-t113-pio" 优先于 "allwinner,sun8i-h3-pio"。
3.6 本章小结
| 概念 | 关键点 | 全志 T113 典型值 |
|---|---|---|
| DTS → DTB | 通过 DTC 编译,U-Boot 加载 | sun8i-t113.dts → sun8i-t113.dtb |
| 节点命名 | 节点名@单元地址 | pinctrl@1c20800 |
| #address-cells | 地址字段宽度(32 位字) | 1(32 位地址空间) |
| #size-cells | 长度字段宽度(32 位字) | 1(最大 4GB) |
| reg | 地址-长度对,描述硬件地址空间 | <0x01c20800 0x400> |
| compatible | 驱动匹配字符串,支持多级回退 | "allwinner,sun8i-t113-pio" |