4. 设备树节点与属性详解:compatible、reg、interrupts、status等核心属性的含义与用法
设备树(Device Tree)的核心价值在于通过节点(Node)与属性(Property)的层级结构,将板级硬件信息以标准化的方式传递给操作系统内核。本章将深入解析最常用的核心属性,包括它们的语法、语义、典型用法以及常见陷阱。
4.1 节点与属性的基础结构
设备树是一个树形结构,每个节点代表一个硬件设备或总线,节点内包含若干属性来描述其特性。一个典型的节点结构如下:
device_name@address {
compatible = "vendor,device";
reg = <base_addr size>;
interrupts = <interrupt_spec>;
status = "okay";
// 其他属性...
};
节点名称通常由通用名称和单元地址(@后面的部分)组成,单元地址一般对应设备的起始寄存器地址,用于区分同一总线上的多个相同设备。
4.2 compatible 属性:设备驱动匹配的关键
compatible 属性是设备树中最重要的属性之一,它建立了硬件设备与内核驱动之间的匹配关系。其值是一个字符串列表,格式为 "厂商,设备型号"。
4.2.1 语法与规范
compatible = "vendor,device", "fallback_device";
第一个字符串是精确匹配,后续字符串是兼容匹配(回退方案)。内核在匹配驱动时,会按照列表顺序依次尝试。
| 匹配方式 | 示例 | 说明 |
|---|---|---|
| 精确匹配 | "fsl,imx6ull-uart" |
仅匹配 i.MX6ULL 的 UART 驱动 |
| 兼容匹配 | "ns16550" |
回退到标准 16550 UART 驱动 |
| 多级兼容 | "ti,am3359-uart", "ti,omap3-uart" |
先匹配 AM3359,再回退到 OMAP3 |
4.2.2 驱动匹配流程
当内核启动时,设备树解析器会遍历所有节点,并将节点的 compatible 属性与驱动注册的 of_device_id 表进行匹配。匹配成功则调用驱动的 probe 函数。
4.3 reg 属性:描述设备地址空间
reg 属性用于描述设备在总线上的地址空间,包括寄存器基地址和地址范围。其格式依赖于父节点的 #address-cells 和 #size-cells 属性。
4.3.1 地址单元与大小单元
// 父节点定义地址格式
soc {
#address-cells = <1>; // 地址用 1 个 32 位整数表示
#size-cells = <1>; // 大小用 1 个 32 位整数表示
uart@1f000 {
reg = <0x1f000 0x1000>; // 基址 0x1f000,范围 0x1000
};
};
// 64 位地址示例
bus {
#address-cells = <2>; // 地址用 2 个 32 位整数(64 位)
#size-cells = <2>; // 大小用 2 个 32 位整数(64 位)
dma@0x100000000 {
reg = <0x1 0x00000000 0x0 0x10000000>;
// 地址 = 0x100000000,大小 = 0x10000000
};
};
| 属性 | 含义 | 典型值 |
|---|---|---|
#address-cells |
地址字段占用的 32 位整数个数 | 1(32位地址)、2(64位地址) |
#size-cells |
大小字段占用的 32 位整数个数 | 0(无大小)、1(32位大小)、2(64位大小) |
reg |
地址和大小交替排列的数组 | <addr1 size1 addr2 size2 ...> |
4.3.2 多段地址空间
一个设备可能拥有多个不连续的地址段,例如 FIFO 和控制寄存器分离:
ethernet@10000000 {
compatible = "vendor,gmac";
reg = <0x10000000 0x1000 // 控制寄存器
0x20000000 0x2000>; // DMA 描述符区
};
of_iomap() 或 platform_get_resource() 获取 reg 属性定义的地址资源。多段地址通过索引号(0、1、2...)区分。
4.4 interrupts 属性:中断资源描述
interrupts 属性描述设备使用的中断资源,其格式由父节点的 #interrupt-cells 属性定义。中断控制器节点(如 GIC)负责解释这些值。
4.4.1 中断描述格式
// ARM GIC 中断控制器示例
gic: interrupt-controller@1e00000 {
compatible = "arm,cortex-a7-gic";
#interrupt-cells = <3>; // 每个中断用 3 个 32 位整数描述
interrupt-controller; // 标记本节点为中断控制器
};
// 设备节点使用中断
uart@1f000 {
compatible = "vendor,uart";
reg = <0x1f000 0x1000>;
interrupts = <0 33 4>; // 类型 SPI,中断号 33,触发方式 4
interrupt-parent = <&gic>; // 指定中断控制器
};
| 字段 | 含义 | 常见值 |
|---|---|---|
| 中断类型 | 0=PPI(私有外设中断),1=SPI(共享外设中断) | 0 或 1 |
| 中断号 | 相对于中断控制器的中断编号 | 32~1019(SPI) |
| 触发方式 | 1=上升沿,2=下降沿,4=高电平,8=低电平 | 1、2、4、8 |
4.4.2 中断映射与级联
当系统中有多个中断控制器时,通过 interrupt-map 和 interrupt-parent 实现中断的层级映射。
4.5 status 属性:设备状态控制
status 属性用于控制设备是否启用,是板级配置中最常用的属性之一。它允许 SoC 级 .dtsi 文件中定义所有外设,然后在板级 .dts 文件中选择性启用或禁用。
| 状态值 | 含义 | 使用场景 |
|---|---|---|
"okay" |
设备启用,驱动正常加载 | 板级文件中启用 SoC 定义的外设 |
"disabled" |
设备禁用,驱动不加载 | SoC 级文件中默认关闭未使用的外设 |
"reserved" |
设备保留,操作系统不管理 | 固件或安全世界使用的设备 |
"fail" |
设备检测失败 | 硬件探测后由 Bootloader 设置 |
4.5.1 典型用法:分层覆盖
// imx6ull.dtsi(SoC 级,默认关闭)
uart1: serial@1f000 {
compatible = "fsl,imx6ull-uart", "fsl,imx6q-uart";
reg = <0x1f000 0x1000>;
interrupts = <0 33 4>;
status = "disabled"; // 默认关闭
};
// my-board.dts(板级,按需启用)
#include "imx6ull.dtsi"
&uart1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart1>;
status = "okay"; // 板级启用
};
4.6 其他常用属性
除了上述核心属性外,设备树中还有大量标准属性用于描述设备的特定功能:
| 属性 | 用途 | 示例 |
|---|---|---|
clock |
指定设备使用的时钟源 | clocks = <&clk IMX6ULL_CLK_UART1>; |
pinctrl |
引脚复用配置 | pinctrl-0 = <&pinctrl_uart1>; |
dmas |
DMA 通道配置 | dmas = <&sdma 1 2>; |
power-domains |
电源域管理 | power-domains = <&pd_core>; |
resets |
复位信号控制 | resets = <&rst 10>; |
memory-region |
保留内存区域 | memory-region = <&vdev0buffer>; |
4.7 属性使用综合示例
以下是一个完整的 I2C 控制器及其从设备节点的示例,展示了多个核心属性的协同使用:
// I2C 控制器节点
i2c1: i2c@21a0000 {
compatible = "fsl,imx6ull-i2c", "fsl,imx6q-i2c";
reg = <0x021a0000 0x4000>;
interrupts = <0 36 4>;
clocks = <&clks IMX6ULL_CLK_I2C1>;
status = "disabled";
#address-cells = <1>;
#size-cells = <0>;
// I2C 从设备:温度传感器
temp_sensor: temperature@48 {
compatible = "ti,tmp102";
reg = <0x48>; // I2C 从设备地址
interrupts = <5 2>; // GPIO 中断
interrupt-parent = <&gpio1>;
status = "okay";
};
// I2C 从设备:EEPROM
eeprom@50 {
compatible = "atmel,24c02";
reg = <0x50>;
pagesize = <16>;
status = "okay";
};
};
- compatible:驱动匹配的核心,格式为 "厂商,设备型号"
- reg:描述地址空间,格式由父节点的 #address-cells 和 #size-cells 决定
- interrupts:中断资源描述,格式由中断控制器的 #interrupt-cells 决定
- status:设备状态控制,"okay" 启用,"disabled" 禁用
- 所有属性共同构成完整的硬件描述,驱动通过标准 API 解析这些属性