2. 设备树基础语法:节点、属性、reg、compatible、status等核心概念
设备树(Device Tree)是一种描述硬件资源的数据结构,它使用节点(Node)和属性(Property)的层级关系,将非可枚举的硬件信息传递给操作系统内核。在Linux网络设备驱动中,MAC控制器、DMA引擎、PHY芯片、MDIO总线等硬件单元,都通过设备树节点进行描述和关联。掌握设备树的基础语法,是解析MAC节点到PHY绑定路径的前提。
2.1 节点(Node)与属性(Property)
设备树的基本单元是节点。每个节点代表一个硬件设备、总线、控制器或功能块。节点可以嵌套,形成树状结构。节点内部包含属性,属性是键值对,用于描述节点的特征。
/dts-v1/;
/ {
model = "Embedded ARM Board";
compatible = "vendor,board-v1", "vendor,board";
soc {
compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
eth0: ethernet@10000000 {
compatible = "vendor,mac-controller";
reg = <0x10000000 0x1000>;
interrupts = <0 33 4>;
status = "okay";
};
};
};
node-name@unit-address。其中 node-name 是通用名称(如 ethernet、i2c、gpio),unit-address 是设备在总线上的地址(如寄存器基址、I2C从机地址)。eth0: 是标签(label),用于在其他地方引用该节点。
下表总结了节点和属性的基本构成要素:
| 元素 | 语法 | 说明 | 示例 |
|---|---|---|---|
| 根节点 | / { }; |
设备树的顶层容器,代表整个板级硬件 | / { model = "..." }; |
| 子节点 | node-name { }; |
在父节点内部定义,可嵌套任意层级 | soc { ethernet@... }; |
| 标签 | label: |
节点别名,用于引用或覆盖节点 | eth0: ethernet@10000000 |
| 属性 | key = value; |
键值对,值可以是字符串、数字、数组等 | status = "okay"; |
| 引用 | &label |
通过标签引用节点,用于追加或修改属性 | ð0 { phy-handle = &phy0; }; |
2.2 核心属性详解
设备树规范定义了一组标准属性,用于描述硬件资源的分配和设备的标识。对于网络设备驱动,以下四个属性最为关键:compatible、reg、interrupts 和 status。
2.2.1 compatible —— 驱动匹配的“身份证”
compatible 属性是设备节点与驱动代码之间的绑定桥梁。它的值是一个字符串列表,格式通常为 "厂商,设备型号"。内核在启动时,遍历所有设备节点,将节点的 compatible 值与驱动注册的 of_match_table 进行匹配。
// 设备树节点
ethernet@10000000 {
compatible = "vendor,mac-controller-v2", "vendor,mac-controller";
// 内核匹配时,优先使用第一个字符串
};
// 驱动中的匹配表
static const struct of_device_id mac_dt_ids[] = {
{ .compatible = "vendor,mac-controller-v2", .data = &mac_v2_data },
{ .compatible = "vendor,mac-controller", .data = &mac_v1_data },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, mac_dt_ids);
2.2.2 reg —— 地址空间描述
reg 属性描述设备在总线上的地址区域。它由一组地址+长度对组成,每个对的解释依赖于父节点的 #address-cells 和 #size-cells 属性。
| 父节点属性 | 含义 | reg 示例 | 解释 |
|---|---|---|---|
#address-cells = <1>#size-cells = <1> |
32位地址,32位长度 | reg = <0x10000000 0x1000>; |
基址 0x10000000,长度 0x1000(4KB) |
#address-cells = <2>#size-cells = <2> |
64位地址,64位长度 | reg = <0x0 0x10000000 0x0 0x1000>; |
基址 0x10000000(高32位0),长度 0x1000 |
#address-cells = <1>#size-cells = <0> |
32位地址,无长度(I2C/SPI从设备) | reg = <0x1c>; |
I2C从机地址 0x1c |
// 典型MAC节点reg定义
eth0: ethernet@10000000 {
compatible = "vendor,mac";
reg = <0x10000000 0x1000>; // MAC控制寄存器
reg-names = "mac_regs"; // 可选:给reg区域命名
interrupts = <0 33 4>; // 中断描述
interrupt-names = "mac_irq"; // 可选:给中断命名
};
2.2.3 interrupts —— 中断资源描述
interrupts 属性描述设备使用的中断线。它的格式依赖于父节点(通常是中断控制器)的 #interrupt-cells 属性。对于ARM GIC(通用中断控制器),通常使用3个cell:
- 第一个cell:中断类型(0=SPI共享外设中断,1=PPI私有外设中断)
- 第二个cell:中断号(SPI从32开始编号,PPI从16开始编号)
- 第三个cell:中断触发方式(1=上升沿触发,2=下降沿触发,4=高电平触发,8=低电平触发)
// 中断控制器定义
gic: interrupt-controller@10480000 {
compatible = "arm,cortex-a9-gic";
#interrupt-cells = <3>;
interrupt-controller;
reg = <0x10480000 0x1000>,
<0x10490000 0x1000>;
};
// 使用中断的MAC节点
eth0: ethernet@10000000 {
compatible = "vendor,mac";
reg = <0x10000000 0x1000>;
interrupts = <0 33 4>; // SPI中断号33,高电平触发
interrupt-parent = <&gic>; // 指定中断控制器
};
2.2.4 status —— 设备状态控制
status 属性用于控制设备节点的启用或禁用状态。它允许在不修改硬件描述的情况下,通过设备树覆盖来启用或禁用某个外设。
| status 值 | 含义 | 使用场景 |
|---|---|---|
"okay" |
设备已启用,驱动应正常探测 | 默认启用的外设 |
"disabled" |
设备已禁用,驱动不会探测 | 硬件存在但当前未使用,或引脚被复用 |
"reserved" |
设备保留,操作系统不应使用 | 由固件或安全世界使用的设备 |
"fail" |
设备检测失败,不可用 | 硬件自检失败时由bootloader设置 |
// 在板级dts中覆盖禁用某个MAC
ð1 {
status = "disabled"; // 第二个以太网口硬件存在但未使用
};
// 在另一款变体板中重新启用
ð1 {
status = "okay";
phy-handle = <&phy1>;
};
2.3 特殊属性与常用节点类型
除了上述核心属性外,设备树还定义了一些特殊属性和节点类型,在网络驱动中频繁出现:
| 属性/节点 | 语法 | 网络驱动中的用途 |
|---|---|---|
#address-cells |
#address-cells = <1>; |
定义子节点 reg 属性中地址字段的32位字数量 |
#size-cells |
#size-cells = <1>; |
定义子节点 reg 属性中长度字段的32位字数量 |
reg-names |
reg-names = "mac", "dma"; |
为多个 reg 区域命名,驱动通过名称获取对应地址 |
interrupt-names |
interrupt-names = "rx", "tx"; |
为多个中断命名,驱动通过名称获取对应中断号 |
clocks |
clocks = <&clk MAC_CLK>; |
指定设备使用的时钟源,MAC驱动需要时钟使能 |
resets |
resets = <&rst MAC_RST>; |
指定设备复位控制器,用于硬件复位 |
phy-handle |
phy-handle = <&phy0>; |
MAC节点引用PHY节点,建立MAC-PHY绑定关系 |
phy-mode |
phy-mode = "rgmii"; |
指定MAC与PHY之间的接口模式(MII/RMII/RGMII等) |
fixed-link |
fixed-link { speed = <1000>; full-duplex; }; |
当PHY不存在或为固定速率时,模拟PHY链接状态 |
// 完整的MAC节点示例(包含常用属性)
ð0 {
status = "okay";
compatible = "vendor,mac-v3", "vendor,mac";
reg = <0x10000000 0x1000>,
<0x10001000 0x100>; // MAC寄存器 + DMA控制寄存器
reg-names = "mac_regs", "dma_regs";
interrupts = <0 33 4>, <0 34 4>; // MAC中断 + DMA中断
interrupt-names = "mac_irq", "dma_irq";
clocks = <&clk MAC_CLK>, <&clk MAC_AXI_CLK>;
clock-names = "mac_clk", "axi_clk";
resets = <&rst MAC_RST>;
reset-names = "mac_rst";
phy-handle = <&phy0>;
phy-mode = "rgmii-id";
mac-address = [00 11 22 33 44 55]; // 可选:预设MAC地址
};
2.4 设备树包含与覆盖机制
在实际项目中,设备树文件通常分为多个层级:.dtsi(包含文件,定义SoC级硬件)和.dts(板级文件,定义具体板级硬件)。板级文件通过 #include 包含SoC的dtsi文件,然后通过标签引用覆盖或追加属性。
// soc.dtsi —— SoC级定义
soc {
#address-cells = <1>;
#size-cells = <1>;
compatible = "simple-bus";
eth0: ethernet@10000000 {
compatible = "vendor,mac";
reg = <0x10000000 0x1000>;
interrupts = <0 33 4>;
status = "disabled"; // SoC级默认禁用
};
};
// board.dts —— 板级文件
#include "soc.dtsi"
ð0 {
status = "okay"; // 板级启用
phy-handle = <&phy0>;
phy-mode = "rgmii";
pinctrl-0 = <ð0_pins>;
pinctrl-names = "default";
};
2.5 本章小结
设备树基础语法是理解网络设备驱动的基石。通过本章的学习,你应该掌握:
- 节点与属性的层级关系:根节点→总线节点→设备节点→子设备节点
- compatible 属性:驱动匹配的核心,格式为"厂商,设备型号",支持兼容性列表
- reg 属性:描述地址空间,受父节点 #address-cells/#size-cells 控制
- interrupts 属性:描述中断资源,格式由中断控制器定义
- status 属性:控制设备启用/禁用,支持板级覆盖
- 网络专用属性:phy-handle、phy-mode、fixed-link 等用于MAC-PHY绑定
- 包含与覆盖机制:.dtsi 定义SoC级硬件,.dts 定义板级配置