3、设备树常用属性详解:compatible、reg、interrupts、status、clocks、resets 等
设备树(Device Tree)中的属性(property)是描述硬件配置与连接关系的关键载体。每个节点通过一组标准属性向内核传递设备类型、地址映射、中断路由、时钟与复位依赖等信息。本章将逐一拆解最常用的六大属性,并结合实际案例说明其解析规则与常见陷阱。
3.1 compatible —— 设备驱动匹配的“身份证”
compatible 属性是设备树中最核心的字符串列表属性,用于将设备节点与内核驱动进行绑定。内核在启动时遍历设备树,通过 of_match_table 逐一比对节点的 compatible 值,找到匹配的驱动后执行 probe。
| 字段 | 说明 | 示例 |
|---|---|---|
| 厂商前缀 | 标识设备制造商,通常与 vendor-prefix 绑定 | ti, fsl, samsung, |
| 设备型号 | 具体芯片或 IP 核名称 | am335x-uart imx6q-ecspi |
| 兼容列表 | 从最具体到最通用,内核按顺序匹配 | "ti,am335x-uart", "ns16550" |
// 典型 compatible 写法
uart0: serial@44e09000 {
compatible = "ti,am335x-uart", "ns16550";
reg = <0x44e09000 0x2000>;
interrupts = <72>;
};
匹配优先级:内核优先匹配列表中的第一个字符串。若第一个驱动未注册,则尝试第二个。建议将最精确的型号放在最前,通用型号放在其后,以兼顾精确匹配与向后兼容。
3.2 reg —— 地址空间与内存映射
reg 属性描述设备在系统总线上的地址范围,由一组或多组 (address, length) 对组成。其解析依赖于父节点的 #address-cells 和 #size-cells 属性。
// 32 位地址空间示例
sram@80000000 {
compatible = "mmio-sram";
reg = <0x80000000 0x10000>; // 起始地址 0x80000000,长度 64KB
};
// 64 位地址空间示例
pcie@4000000000 {
compatible = "pci-host-ecam-generic";
reg = <0x00000040 0x00000000 0x0 0x10000000>; // 高32位 低32位 长度高32位 长度低32位
#address-cells = <3>;
#size-cells = <2>;
};
| 父节点属性 | 含义 | 典型值 |
|---|---|---|
#address-cells |
每个地址占用的 32 位单元数 | 1(32位地址)或 2(64位地址) |
#size-cells |
每个长度占用的 32 位单元数 | 1(32位长度)或 2(64位长度) |
常见错误:当父节点使用
#address-cells = <2> 时,子节点 reg 中的地址必须写满两个 32 位单元,否则内核解析会错位,导致 ioremap 映射到错误的物理地址。
3.3 interrupts —— 中断路由与触发类型
interrupts 属性描述设备的中断请求线,包含中断号、触发类型等信息。其解析依赖于父节点或中断控制器的 #interrupt-cells 属性。
// 简单中断控制器(GIC)
gic: interrupt-controller@f0001000 {
compatible = "arm,cortex-a9-gic";
#interrupt-cells = <3>;
interrupt-controller;
reg = <0xf0001000 0x1000>;
};
// 设备节点使用中断
uart@44e09000 {
compatible = "ti,am335x-uart", "ns16550";
reg = <0x44e09000 0x2000>;
interrupts = <0 72 4>; // 中断类型 0(SPI) 中断号72 触发类型4(高电平)
};
| 中断类型(GIC 三单元) | 值 | 说明 |
|---|---|---|
| 中断类型 | 0 = SPI, 1 = PPI | SPI 共享外设中断,PPI 私有外设中断 |
| 中断号 | 32~1019(SPI) | 实际硬件中断线编号 |
| 触发类型 | 1 = 上升沿, 4 = 高电平 | 决定中断检测方式 |
3.4 status —— 设备启用状态控制
status 属性用于控制设备节点的启用或禁用状态,是板级适配中最常用的开关属性之一。内核在解析设备树时,会检查该属性决定是否创建设备并调用驱动。
| status 值 | 含义 | 内核行为 |
|---|---|---|
"okay" |
设备启用 | 正常创建设备并匹配驱动 |
"disabled" |
设备禁用 | 跳过该节点,不创建设备 |
"fail" |
设备故障 | 标记为失败,不 probe |
| 缺失 | 默认启用 | 视为 "okay"(部分架构有差异) |
// SoC 级 dtsi 中默认禁用
uart1: serial@44e09000 {
compatible = "ti,am335x-uart", "ns16550";
reg = <0x44e09000 0x2000>;
interrupts = <72>;
status = "disabled";
};
// 板级 dts 中启用
&uart1 {
status = "okay";
};
最佳实践:SoC 级
.dtsi 文件应将所有外设默认设为 disabled,板级 .dts 文件按需启用。这样可以避免未使用的设备占用资源,同时减少板级适配时的冲突。
3.5 clocks —— 时钟源与时钟门控
clocks 属性描述设备所需的时钟源,通常与 clock-names 配合使用。内核通过时钟框架(CCF)获取时钟句柄,用于使能、设置频率或门控操作。
// 时钟控制器定义
clocks {
uart_clk: clock@0 {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <48000000>;
};
};
// 设备节点引用时钟
uart0: serial@44e09000 {
compatible = "ti,am335x-uart", "ns16550";
reg = <0x44e09000 0x2000>;
interrupts = <72>;
clocks = <&uart_clk>;
clock-names = "uart_clk";
};
| 属性 | 类型 | 说明 |
|---|---|---|
clocks |
phandle 列表 | 指向时钟控制器的句柄,可包含多个时钟 |
clock-names |
字符串列表 | 为每个时钟指定名称,便于驱动通过名称查找 |
assigned-clocks |
phandle 列表 | 指定需要初始化的时钟,配合 assigned-clock-rates 使用 |
3.6 resets —— 复位信号控制
resets 属性描述设备所需的复位信号,通常与 reset-names 配合使用。内核通过复位框架(reset controller framework)管理设备的复位与释放时序。
// 复位控制器定义
rstc: reset-controller@44e00000 {
compatible = "ti,am335x-reset";
#reset-cells = <1>;
reg = <0x44e00000 0x1000>;
};
// 设备节点引用复位
mmc0: mmc@48060000 {
compatible = "ti,am335x-mmc";
reg = <0x48060000 0x1000>;
interrupts = <64>;
clocks = <&mmc_clk>;
clock-names = "mmc_clk";
resets = <&rstc 5>; // 复位控制器句柄 + 复位 ID
reset-names = "mmc_rst";
};
| 属性 | 类型 | 说明 |
|---|---|---|
resets |
phandle + 参数列表 | 指向复位控制器的句柄,参数由 #reset-cells 决定 |
reset-names |
字符串列表 | 为每个复位信号命名,便于驱动查找 |
复位时序要点:驱动在 probe 阶段应调用
devm_reset_control_get() 获取复位句柄,并在设备初始化前调用 reset_control_deassert() 释放复位,确保设备处于正常工作状态。对于共享复位信号,需注意多个设备之间的复位依赖关系。
3.7 属性组合实战案例
以下是一个完整的 I2C 控制器设备树节点,展示了上述属性的组合使用方式:
i2c0: i2c@44e0b000 {
compatible = "ti,am335x-i2c", "ti,omap4-i2c";
reg = <0x44e0b000 0x1000>;
interrupts = <70>;
clocks = <&i2c_clk>;
clock-names = "i2c_clk";
resets = <&rstc 3>;
reset-names = "i2c_rst";
status = "okay";
#address-cells = <1>;
#size-cells = <0>;
eeprom@50 {
compatible = "atmel,24c02";
reg = <0x50>;
status = "okay";
};
};
调试建议:当设备无法正常 probe 时,按以下顺序检查设备树属性:
1.
2.
3.
4.
5.
1.
compatible 是否与驱动匹配表一致2.
status 是否为 "okay"3.
clocks 对应的时钟是否已使能4.
resets 对应的复位是否已释放5.
interrupts 中断号是否与其他设备冲突