2. 设备树节点与属性:节点命名规则、标准属性详解
设备树(Device Tree,DT)是嵌入式 Linux 中用于描述硬件拓扑结构的数据结构。它通过节点(Node)和属性(Property)将非可枚举的硬件信息传递给内核。本章将深入讲解节点的命名规范以及三个最核心的标准属性:compatible、reg 和 status。
学习目标:掌握设备树节点的合法命名规则;理解
compatible 属性在驱动匹配中的核心作用;学会使用 reg 属性描述地址空间;掌握 status 属性控制设备启用/禁用的方法。
2.1 节点命名规则
设备树中的每个节点都必须遵循严格的命名规范,以确保解析器能够正确识别。节点名由两部分组成:节点名称和可选的单元地址。
2.1.1 基本格式
node-name@unit-address
- node-name:描述设备通用类型,必须使用小写字母、数字、连字符(-)或下划线(_)组成,长度不超过 31 个字符。例如:
uart、i2c、gpio-controller。 - @unit-address:可选部分,用于区分同一总线上的多个同类型设备。通常为设备在父总线上的起始地址(十六进制)。例如:
serial@101f0000。
2.1.2 命名规则速查表
| 规则项 | 要求 | 合法示例 | 非法示例 |
|---|---|---|---|
| 字符集 | 小写字母、数字、连字符、下划线 | spi-controller |
SPI_CTRL(大写) |
| 长度限制 | ≤ 31 个字符 | ethernet-phy@0 |
very-long-device-name-example@0(超长) |
| 单元地址 | 十六进制,无 0x 前缀 | uart@1c28000 |
uart@0x1c28000 |
| 根节点 | 固定为 / |
/ |
无 |
2.1.3 节点命名与设备类型对应关系
为了保持设备树的可读性,社区推荐使用标准化的节点名称。以下为常见设备类型与其推荐节点名的对照表:
| 设备类型 | 推荐节点名 | 说明 |
|---|---|---|
| CPU | cpu |
每个 CPU 核心一个子节点 |
| 内存 | memory |
描述物理内存布局 |
| 中断控制器 | interrupt-controller |
GIC、INTC 等 |
| GPIO 控制器 | gpio-controller |
通用 GPIO 模块 |
| 串口 | serial |
UART 设备 |
| I2C 控制器 | i2c |
I2C 总线适配器 |
| SPI 控制器 | spi |
SPI 总线适配器 |
| 以太网 | ethernet |
MAC 层控制器 |
最佳实践:在编写设备树时,优先使用上述推荐节点名。如果设备类型不在列表中,使用
generic-device 格式,并确保 compatible 属性足够具体以区分硬件。
2.2 标准属性详解
设备树属性是键值对,用于描述节点的特征。以下三个属性是所有设备树节点中最基础、最常用的标准属性。
2.2.1 compatible 属性:驱动匹配的桥梁
compatible 属性是设备树与内核驱动之间建立关联的核心机制。它包含一个或多个字符串,用于指定设备所兼容的硬件型号。
语法格式:
compatible = "manufacturer,model", "fallback-model";
- 第一个字符串:精确的硬件型号,格式为
"厂商,设备型号"。例如:"ti,am3359-uart"。 - 后续字符串:兼容的通用型号,用于驱动回退匹配。例如:
"ns16550a"。
匹配优先级:内核在注册平台驱动时,会按照 of_match_table 中定义的顺序与设备树的 compatible 列表进行匹配。匹配顺序为:精确匹配 → 回退匹配。
| 匹配类型 | 设备树 compatible | 驱动 of_match_table | 匹配结果 |
|---|---|---|---|
| 精确匹配 | "ti,am3359-uart" |
"ti,am3359-uart" |
✅ 匹配成功 |
| 回退匹配 | "ti,am3359-uart", "ns16550a" |
"ns16550a" |
✅ 匹配成功(回退) |
| 不匹配 | "ti,am3359-uart" |
"snps,dw-apb-uart" |
❌ 匹配失败 |
常见错误:compatible 字符串中厂商名和设备名之间必须使用逗号分隔,且逗号后不能有空格。例如:
"ti,am3359-uart" 正确,"ti, am3359-uart" 错误。
2.2.2 reg 属性:地址空间描述
reg 属性用于描述设备在父总线上的地址空间。它由一组或多组 (address, length) 对组成,具体含义由父节点的 #address-cells 和 #size-cells 属性决定。
语法格式:
reg = <address1 length1 address2 length2 ...>;
地址单元与大小单元:
| 父节点属性 | 含义 | 常见值 |
|---|---|---|
#address-cells |
地址字段占用的 32 位单元数 | 1(32位地址)或 2(64位地址) |
#size-cells |
长度字段占用的 32 位单元数 | 1(32位长度)或 0(无长度) |
示例解析:
// 父节点定义
soc {
#address-cells = <1>; // 地址为 32 位
#size-cells = <1>; // 长度为 32 位
uart@1c28000 {
compatible = "snps,dw-apb-uart";
reg = <0x1c28000 0x1000>; // 起始地址 0x1c28000,长度 0x1000
interrupts = <0 39 4>;
};
};
上述示例中,reg = <0x1c28000 0x1000> 表示 UART 设备占用从物理地址 0x1c28000 开始的 0x1000(4KB)地址空间。
2.2.3 status 属性:设备状态控制
status 属性用于指示设备的启用状态。它允许在不修改硬件描述的情况下,通过设备树覆盖来启用或禁用设备。
| status 值 | 含义 | 使用场景 |
|---|---|---|
"okay" |
设备已启用且功能正常 | 默认启用状态 |
"disabled" |
设备被禁用,内核不会为其创建平台设备 | 硬件存在但未使用,或需要由其他固件配置 |
"reserved" |
设备已被保留,内核不应使用 | 由安全固件或 Hypervisor 占用 |
"fail" |
设备检测失败,不可用 | 硬件自检未通过 |
"fail-sss" |
设备因特定原因失败,sss 为错误码 | 提供更详细的失败原因 |
覆盖机制:在设备树包含(include)或叠加(overlay)中,可以通过重新定义
status 属性来改变设备状态。例如,在基础设备树中设置 status = "disabled",在板级设备树中覆盖为 status = "okay"。
2.3 综合示例:完整的中断控制器节点
以下是一个包含上述所有标准属性的实际设备树节点示例,展示了一个 ARM GIC(通用中断控制器)的典型描述:
// 中断控制器节点
intc: interrupt-controller@1c81000 {
compatible = "arm,cortex-a9-gic";
#interrupt-cells = <3>; // 每个中断描述占用 3 个单元
#address-cells = <0>; // 无子地址
interrupt-controller; // 标记为中断控制器
reg = <0x1c81000 0x1000>, // GIC 分配器寄存器
<0x1c82000 0x2000>; // GIC CPU 接口寄存器
status = "okay"; // 设备启用
};
关键点:
compatible = "arm,cortex-a9-gic"确保内核使用正确的 GIC 驱动。reg包含两段地址空间:分配器(Distributor)和 CPU 接口(CPU Interface)。status = "okay"明确告知内核该中断控制器已就绪。
2.4 本章小结
- 节点命名:遵循
node-name@unit-address格式,名称使用小写字母和连字符,地址为十六进制无前缀。 - compatible:驱动匹配的核心,使用
"厂商,型号"格式,支持回退匹配。 - reg:描述地址空间,由
#address-cells和#size-cells决定格式。 - status:控制设备启用/禁用,支持通过设备树覆盖进行动态调整。
课后练习:编写一个 SPI 控制器的设备树节点,要求:节点名为
spi@1c05000,compatible 为 "snps,dw-apb-ssi",reg 地址范围为 0x1c05000 长度 0x1000,状态为启用。