3. 设备树基础:语法、节点与属性、标准属性及文件组织
设备树(Device Tree,DT)是嵌入式 Linux 中用于描述硬件拓扑结构的数据结构,它替代了传统板级文件(board-*.c)中硬编码的硬件信息。在 USB 驱动移植中,设备树是连接 SoC 控制器与物理 USB 端口的关键桥梁。本章将系统讲解设备树的语法、核心节点与属性、标准属性含义以及 dts/dtsi 文件的组织方式。
3.1 设备树语法基础
设备树源文件(.dts)采用树形结构,以节点(node)和属性(property)描述硬件。每个节点代表一个硬件设备或总线,属性则描述设备的配置参数。
3.1.1 节点定义与层次结构
节点以 节点名@单元地址 的形式定义,通过花括号 { } 包含子节点。根节点是 /,所有设备都挂载在根节点下。
/dts-v1/;
/ {
model = "Embedded USB Dev Board";
compatible = "vendor,board-rev1";
#address-cells = <1>;
#size-cells = <1>;
soc {
compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
ranges;
usb_controller: usb@1c14000 {
compatible = "vendor,usb-otg";
reg = <0x01c14000 0x400>;
interrupts = <0 39 4>;
status = "disabled";
};
};
};
- 节点名:如
usb@1c14000,@ 后为寄存器基地址,用于区分同名设备。 - 标签(label):如
usb_controller:,可在其他位置通过&usb_controller引用。 - 属性值:用
;结尾,支持字符串、整数、字节数组、<>包裹的 32 位整数列表。
3.1.2 属性类型与写法
| 属性类型 | 语法示例 | 说明 |
|---|---|---|
| 字符串 | compatible = "vendor,device"; |
用于匹配驱动,格式为“厂商,设备型号” |
| 32 位整数 | reg = <0x1000 0x200>; |
地址与长度对,由 #address-cells 和 #size-cells 决定数量 |
| 布尔值 | status = "okay"; |
字符串形式,常用 "okay" 或 "disabled" |
| 字节数组 | local-mac-address = [00 11 22 33 44 55]; |
十六进制字节序列,用空格分隔 |
| 字符串列表 | clock-names = "usb_phy", "usb_hclk"; |
多个字符串用空格分隔 |
3.2 标准属性详解
设备树规范定义了一组标准属性,所有设备节点都应遵循。对于 USB 驱动移植,以下三个属性最为关键。
3.2.1 compatible —— 驱动匹配的钥匙
compatible 是设备树中最核心的属性,内核通过它查找对应的驱动程序。格式为 "厂商,设备型号",按优先级从高到低排列。
// USB 控制器节点示例
usb@1c14000 {
compatible = "vendor,usb-otg-v2", "vendor,usb-otg", "generic-usb";
reg = <0x01c14000 0x400>;
interrupts = <0 39 4>;
};
of_match_table 定义的字符串完全一致,包括大小写和逗号。常见错误是厂商名拼写错误或版本号遗漏。
3.2.2 reg —— 地址与内存映射
reg 描述设备的寄存器地址空间,由 #address-cells 和 #size-cells 决定地址和长度的单元数。对于 32 位系统,通常各为 1。
| 属性 | 含义 | USB 场景示例 |
|---|---|---|
#address-cells |
地址字段占用的 32 位单元数 | <1> 表示 32 位地址 |
#size-cells |
长度字段占用的 32 位单元数 | <1> 表示 32 位长度 |
reg |
地址与长度对列表 | <0x01c14000 0x400> 基址 0x01c14000,长度 0x400 |
3.2.3 interrupts —— 中断路由
interrupts 描述设备使用的中断号、触发类型等信息。其格式由 #interrupt-cells 在中断控制器节点中定义。
// 中断控制器定义(GIC)
gic: interrupt-controller@1c81000 {
compatible = "arm,cortex-a7-gic";
#interrupt-cells = <3>;
interrupt-controller;
reg = <0x01c81000 0x1000>;
};
// USB 设备引用中断
usb@1c14000 {
interrupt-parent = <&gic>; // 指定中断控制器
interrupts = <0 39 4>; // 类型 0(SPI), 中断号 39, 触发类型 4(高电平)
};
#interrupt-cells = <3> 时,第一个字段 0=SPI(共享外设中断)、1=PPI(私有外设中断);第二个字段为中断号;第三个字段为触发类型(1=上升沿、2=下降沿、4=高电平、8=低电平)。
3.3 设备树文件组织:dts 与 dtsi
实际项目中,设备树文件按层次组织:.dtsi 文件存放 SoC 级通用定义,.dts 文件存放板级特定配置。这种分离避免了重复定义,便于维护。
3.3.1 文件层次结构
3.3.2 实际项目中的文件组织
以某 ARM 平台 USB 驱动移植为例,典型文件结构如下:
arch/arm/boot/dts/
├── soc.dtsi # SoC 级定义:USB 控制器、GIC、时钟
│ └── usb_otg: usb@1c14000 {
│ compatible = "vendor,usb-otg";
│ reg = <0x01c14000 0x400>;
│ interrupts = <0 39 4>;
│ status = "disabled"; // 默认关闭
│ };
├── board-common.dtsi # 板级通用配置
│ └── &usb_otg {
│ status = "okay"; // 使能 USB 控制器
│ dr_mode = "otg"; // 双角色模式
│ };
└── my-board.dts # 具体板卡配置
└── #include "board-common.dtsi"
&usb_otg {
vbus-supply = <®_usb_vbus>; // 板级特有:VBUS 电源
};
- SoC 级(.dtsi):只描述硬件存在,不使能任何功能,所有设备默认
status = "disabled"。 - 板级通用(.dtsi):使能 SoC 级设备,配置引脚复用、时钟等通用设置。
- 具体板卡(.dts):覆盖板级特有属性,如电源、GPIO 别名、USB 端口角色。
3.4 USB 设备树节点实战解析
下面是一个完整的 USB OTG 控制器设备树节点,包含所有标准属性和 USB 特有属性。
usb_otg: usb@1c14000 {
compatible = "vendor,usb-otg-v2", "vendor,usb-otg";
reg = <0x01c14000 0x400>;
interrupts = <0 39 4>;
interrupt-parent = <&gic>;
clocks = <&ccu CLK_USB_OTG>, <&ccu CLK_BUS_USB_OTG>;
clock-names = "usb_otg", "bus_usb_otg";
resets = <&ccu RST_USB_OTG>;
reset-names = "usb_otg";
phys = <&usbphy 0>;
phy-names = "usb2-phy";
dr_mode = "otg"; // 可选:host, peripheral, otg
status = "disabled";
};
| 属性 | 说明 | USB 移植常见值 |
|---|---|---|
clocks |
时钟句柄列表,对应 clock-names | USB 控制器时钟、总线时钟 |
resets |
复位控制器句柄 | USB 模块复位 |
phys |
PHY(物理层)句柄 | USB 2.0 PHY 或 USB 3.0 PHY |
dr_mode |
双角色模式 | otg / host / peripheral |
vbus-supply |
VBUS 电源 regulator | 板级特有,需在 .dts 中定义 |
3.5 设备树编译与调试
设备树源文件需要通过 dtc(Device Tree Compiler)编译为二进制 .dtb 文件。内核启动时,bootloader 将 .dtb 传递给内核。
# 编译设备树
dtc -I dts -O dtb -o my-board.dtb my-board.dts
# 反编译查看
dtc -I dtb -O dts -o my-board.dts my-board.dtb
# 检查设备树是否被正确加载(内核启动后)
ls /proc/device-tree/
cat /proc/device-tree/model
/proc/device-tree/ 下对应节点是否存在,以及 compatible 字符串是否与驱动匹配。使用 dtc -I fs -O dts /proc/device-tree/ 可以查看内核当前使用的设备树。
3.6 本章小结
设备树是 USB 驱动移植的硬件描述基础。掌握节点语法、标准属性(compatible/reg/interrupts)以及 dts/dtsi 文件组织方式,是正确配置 USB 控制器的前提。在后续章节中,我们将基于本章知识,具体讲解如何为 USB 主机控制器、设备控制器和 PHY 编写设备树节点。
- compatible 是驱动匹配的唯一标识,必须与驱动代码完全一致。
- reg 描述寄存器地址空间,注意 address-cells 和 size-cells 的匹配。
- interrupts 需要配合 interrupt-parent 使用,格式由中断控制器决定。
- dtsi 定义硬件能力,dts 决定使能哪些能力,遵循“分层覆盖”原则。