设备树节点精讲:compatible / reg / 中断属性配置

发布时间:2026/7/22 6:02:36
设备树节点精讲:compatible / reg / 中断属性配置 设备树节点精讲compatible / reg / 中断属性配置作者黒漂技术佬 | 系列Linux内核配置与移植引言上一篇把设备树的来龙去脉讲清楚了这一篇我们深入到节点内部来看看设备树到底是怎么描述一个硬件的。设备树看起来像 JSON但它的语义远比 JSON 更严格——每一个属性名都有固定的含义写错一个字驱动就找不到设备。本文把最核心的三个属性掰开揉碎来讲compatible谁是谁、reg在哪、interrupts怎么通知。一、设备树节点基本结构一个完整的设备树节点长这样node-nameunit-address { property-name value; compatible vendor,device; reg address size; status okay; sub-node { /* 子节点 */ }; };节点命名规则node-name节点类型名称如uart、i2c、gpiounit-address可选的地址后缀值需与reg属性中的首地址一致label引用其他节点的标签属性值的四种基本格式格式示例说明整数数组 reg 0x1000 0x100;32位大端整数序列字符串 compatible arm,pl011;普通字符串字节数组[ ]mac-address [00 11 22 33 44 55];原始十六进制字节组合引用 clocks clkc 24;引用其他节点 phandle二、compatible 属性——驱动的身份证2.1 定义与格式compatible是设备树中最重要的属性没有之一。它用一个字符串列表告诉内核这个设备是什么驱动通过它来匹配设备。uart0: serial101f1000 { compatible arm,pl011, arm,primecell; reg 0x101f1000 0x1000; };格式规范manufacturer,model第一部分是厂商名arm、ti、nxp、st 等第二部分是设备型号pl011、omap-uart、stm32-usart 等可以用多个字符串从左到右匹配越具体的放前面如果第一个匹配不到内核会尝试下一个2.2 驱动侧如何匹配在驱动代码里compatible对应这样的匹配表// drivers/tty/serial/amba-pl011.cstaticconststructof_device_idsbsa_uart_of_match[]{{.compatiblearm,sbsa-uart},{.compatiblearm,pl011},{/* sentinel */},};MODULE_DEVICE_TABLE(of,sbsa_uart_of_match);staticstructplatform_driverpl011_driver{.driver{.nameuart-pl011,.of_match_tablesbsa_uart_of_match,// ← 在这里匹配 DTS 中的 compatible},};匹配流程DTS: compatible ti,am3352-uart, ns16550a; ↓ 内核: of_match_table 逐个对比 ti,am3352-uart 匹配? → YES → 绑定该驱动 ns16550a 匹配? → (不再尝试)2.3 常见 compatible 示例设备类型compatible 字符串示例ARM GIC 中断控制器arm,gic-400PL011 串口arm,pl011STM32 USARTst,stm32-usartI2C 控制器nxp,lpc1788-i2cGPIO 控制器ti,omap4-gpio以太网卡smsc,lan9115温度传感器nxp,lm75aSD卡控制器rockchip,rk3288-dw-mshc三、reg 属性——寄存器的门牌号3.1 基本格式reg描述了设备的寄存器或内存地址范围reg 起始地址1 大小1 起始地址2 大小2 ...;格式为成对的(address, length)。具体的含义由父节点的#address-cells和#size-cells决定。3.2 address-cells 和 size-cells这两个属性定义在父节点上告诉解析器reg中一个地址或长度占几个 32 位字soc { #address-cells 1; /* 地址用1个32位数表示 */ #size-cells 1; /* 大小用1个32位数表示 */ uart0: serial40002000 { compatible arm,pl011; reg 0x40002000 0x1000; /* ↑ 地址 ↑ 大小 (4KB) */ }; };各种组合示例#address-cells#size-cellsreg 示例适用场景110x4000 0x10032位处理器外设最常见100x123只有地址没有大小如 I2C 设备210x0 0x4000 0x10064位地址空间220x0 0x4000 0x0 0x10064位地址 64位大小3.3 不同类型总线上的 reg内存映射外设MMIOamba { #address-cells 1; #size-cells 1; uart101f1000 { reg 0x101f1000 0x1000; /* 基地址 寄存器范围 */ }; };I2C 从设备i2c0 { #address-cells 1; #size-cells 0; /* I2C 设备没有地址空间概念 */ eeprom50 { /* 50 表示 I2C 从设备地址 0x50 */ compatible atmel,24c02; reg 0x50; /* 这里的 reg 是 I2C 地址不是 MMIO */ }; };SPI 从设备spi0 { #address-cells 1; #size-cells 0; flash0 { /* 0 表示 SPI 片选 CS0 */ compatible spi-nand; reg 0; /* 这里的 reg 是片选编号 */ }; };四、interrupts 属性——硬件如何喊你4.1 基本格式interrupts描述了设备使用的中断信息uart40002000 { compatible arm,pl011; reg 0x40002000 0x1000; interrupts 0 12 4; };这里0 12 4的含义取决于中断控制器的绑定规范。对于 ARM GIC 中断控制器字段含义值 0 12 4 的解释第1个值中断类型0 SPI共享外设中断第2个值中断号12 第12号中断第3个值触发方式4 高电平触发GIC 中断触发方式编码IRQ_TYPE_NONE 0 // 未定义 IRQ_TYPE_EDGE_RISING 1 // 上升沿触发 IRQ_TYPE_EDGE_FALLING 2 // 下降沿触发 IRQ_TYPE_EDGE_BOTH 3 // 双边沿触发 IRQ_TYPE_LEVEL_HIGH 4 // 高电平触发 IRQ_TYPE_LEVEL_LOW 8 // 低电平触发4.2 interrupt-parent 和 interrupts-extended当设备的中断控制器不是它的直接父节点时需要显式指定/* 方式一单独指定 interrupt-parent */ i2c40005000 { compatible vendor,i2c; reg 0x40005000 0x1000; interrupt-parent intc; /* 指定中断控制器 */ interrupts 0 21 4; /* SPI 21, 高电平 */ }; /* 方式二interrupts-extended 一步到位 */ i2c40005000 { compatible vendor,i2c; reg 0x40005000 0x1000; interrupts-extended intc 0 21 4; /* 一行搞定 */ };4.3 中断控制器的固定定义interrupt-controller中断控制器自身在设备树中也有特定的声明intc: interrupt-controller1e001000 { compatible arm,cortex-a9-gic; reg 0x1e001000 0x1000, 0x1e000100 0x100; #interrupt-cells 3; /* interrupts 属性每个单元有3个数 */ interrupt-controller; /* 宣告我是中断控制器 */ };interrupt-controller声明这是一个中断控制器空属性有就表示是#interrupt-cells声明引用该控制器时interrupts属性中每个中断用几个整数来描述GIC 是 3五、其他常用属性速查属性作用示例reg-names给 reg 中的地址区域起名字reg-names base, alias;clocks指定设备使用的时钟源clocks clkc 15;clock-names给时钟起名字clock-names apb_pclk;dmas指定 DMA 通道dmas dmac 0 2;pinctrl-0引脚复用配置pinctrl-0 uart0_pins;gpiosGPIO 引脚引用gpios gpio0 5 0;status设备状态okay/disabled/reservedphandle节点唯一标识通常自动生成DTC 自动为有 label 的节点生成status 的取值含义值含义okay设备可用正常初始化disabled设备不可用硬件存在但软件不用reserved设备预留驱动不配置但不要更改寄存器fail设备探测失败六、实操写一个完整的设备节点综合以上知识下面是 STM32 板卡上一个温度传感器的完整设备树节点i2c1 { #address-cells 1; #size-cells 0; status okay; lm75: temperature-sensor48 { compatible nxp,lm75a; reg 0x48; /* I2C 从设备地址 */ status okay; interrupts-extended gpiof 3 IRQ_TYPE_EDGE_FALLING; /* ↑PF3引脚 下降沿触发 */ #thermal-sensor-cells 0; pinctrl-0 lm75_int_pin; /* 引脚复用 */ }; };逐行解读i2c1—— 引用 SoC 级别定义好的 I2C1 控制器#address-cells 1—— I2C 设备地址用一个整数#size-cells 0—— I2C 没有地址空间48—— 设备 I2C 地址是 0x48传感器硬连接的地址脚决定compatible nxp,lm75a—— 匹配内核的 lm75 驱动reg 0x48—— 确认 I2C 地址要和 后面的值一致interrupts-extended—— 温度超限时通过 PF3 引脚触发中断pinctrl-0—— 指定 PF3 的引脚复用功能总结设备树的三个核心属性记住这个类比compatible 是身份证告诉内核我是谁reg 是门牌号告诉内核我在哪interrupts 是电话号码告诉内核怎么找我。掌握了这三个再加上#address-cells和#size-cells这对规则说明书你就能读写 80% 的设备树节点了。