3. 设备树基础
设备树(Device Tree,DT)是嵌入式 Linux 中用于描述硬件拓扑结构的数据结构,它将硬件信息从内核代码中分离出来,使得同一份内核镜像可以支持多种硬件平台。对于 USB 设备驱动开发而言,设备树是连接 USB 控制器、PHY 芯片与内核驱动之间的“硬件配置清单”。
3.1 设备树语法基础
设备树源文件(.dts)采用树形结构,由节点(node)和属性(property)组成。每个节点代表一个硬件设备或总线,属性则描述设备的特性。
3.1.1 节点定义
节点的基本语法格式如下:
/dts-v1/;
/ {
node1 {
property1 = <value>;
property2 = "string";
child-node {
...
};
};
};
- 根节点:
/表示设备树的根,整个硬件系统从根节点展开。 - 子节点:在父节点内通过
node-name { };定义。 - 节点名称:格式为
name@unit-address,其中unit-address通常是设备在总线上的地址(如寄存器基址)。
usb@xxxxxxx,PHY 节点命名为 usb-phy@xxxxxxx,便于通过名称快速识别设备类型。
3.1.2 属性定义
属性是节点的“键值对”,用于描述设备的硬件特征。常见属性类型如下表:
| 属性类型 | 语法示例 | 说明 |
|---|---|---|
| 32 位整数 | reg = <0x110000 0x1000>; |
地址或配置值,可包含多个值 |
| 字符串 | compatible = "snps,dwc3"; |
用于匹配驱动 |
| 字符串列表 | compatible = "ti,am335x-usb", "ti,musb"; |
多个兼容字符串,按优先级排列 |
| 布尔值 | status = "okay"; |
通过存在与否或特定字符串表示 |
| 二进制数据 | reg = <0x01 0x02 0x03>; |
以字节数组形式编码 |
| phandle | phys = <&usb_phy>; |
引用另一个节点的指针 |
3.2 标准属性详解
设备树规范定义了一组标准属性,所有设备节点都应遵循这些属性的语义。以下逐一解析与 USB 驱动最相关的标准属性。
3.2.1 compatible —— 驱动匹配的关键
compatible 属性是设备树与驱动代码之间的“握手协议”。内核通过该属性查找对应的驱动程序。
usb@fe800000 {
compatible = "snps,dwc3", "generic-dwc3";
reg = <0xfe800000 0x10000>;
};
- 格式:
"厂商,设备型号",可包含多个字符串,从左到右优先级递减。 - 匹配规则:内核遍历
of_match_table,找到第一个匹配的条目即绑定驱动。 - USB 场景:DWC3 控制器常用
"snps,dwc3",EHCI 控制器常用"generic-ehci"。
3.2.2 reg —— 地址与内存映射
reg 属性描述设备的寄存器地址范围,驱动通过它获取 MMIO 基址。
usb@fe800000 {
reg = <0xfe800000 0x10000>; // 基址 0xfe800000,长度 0x10000
};
| 字段 | 含义 | 示例值 |
|---|---|---|
| address-cells | 地址字段占用的 32 位单元数 | 1(32 位地址)或 2(64 位地址) |
| size-cells | 长度字段占用的 32 位单元数 | 1(32 位长度) |
| reg 值 | 交替排列的地址和长度对 | <0xfe800000 0x10000> |
address-cells 为 2,则地址需要写成 <0x00 0xfe800000 0x00 0x10000>,即高 32 位 + 低 32 位 + 高 32 位长度 + 低 32 位长度。
3.2.3 interrupts —— 中断资源配置
USB 控制器通常需要中断来通知事件(如连接/断开、传输完成)。interrupts 属性描述设备使用的中断号与触发方式。
usb@fe800000 {
interrupts = <0 72 4>; // 中断类型 0(SPI),中断号 72,触发方式 4(高电平)
interrupt-parent = <&gic>;
};
| 字段 | 含义 | 常见值 |
|---|---|---|
| 中断类型 | 0=SPI(共享外设中断),1=PPI(私有外设中断) | 0 |
| 中断号 | 硬件中断编号 | 72(取决于 SoC) |
| 触发方式 | 1=上升沿,2=下降沿,4=高电平,8=低电平 | 4(高电平触发) |
3.2.4 status —— 设备启用控制
status 属性控制设备是否被内核启用,常用于在 board 文件中覆盖 SoC 默认配置。
usb@fe800000 {
status = "okay"; // 启用设备
// status = "disabled"; // 禁用设备
};
| 状态值 | 含义 | 使用场景 |
|---|---|---|
"okay" |
设备正常启用 | 板级文件覆盖 SoC 默认禁用状态 |
"disabled" |
设备被禁用,驱动不会 probe | 未使用的 USB 控制器 |
"fail" |
设备存在但无法工作 | 硬件故障或未完成初始化 |
3.2.5 phandle —— 节点引用机制
phandle(pointer handle)是设备树中实现节点间引用的机制。一个节点可以通过 phandle 属性被其他节点引用,通常使用 &label 语法。
usb_phy: usb-phy@e000 {
compatible = "ti,am335x-usb-phy";
reg = <0xe000 0x100>;
#phy-cells = <0>;
};
usb@fe800000 {
compatible = "snps,dwc3";
reg = <0xfe800000 0x10000>;
phys = <&usb_phy>; // 通过 phandle 引用 PHY 节点
phy-names = "usb3-phy";
};
- 定义:在节点前加
label:,如usb_phy:,编译器自动生成phandle。 - 引用:使用
&label语法,如&usb_phy。 - USB 场景:USB 控制器通过
phys属性引用 PHY 节点,实现控制器与 PHY 的绑定。
3.3 设备树层级结构:从 SoC 到 USB 控制器
一个完整的设备树文件通常包含 SoC 级描述和板级描述。以下是一个简化的 USB 设备树层级结构:
/ {
model = "TI AM335x Board";
compatible = "ti,am335x-board";
soc {
#address-cells = <1>;
#size-cells = <1>;
ranges;
usb_phy: usb-phy@e000 {
compatible = "ti,am335x-usb-phy";
reg = <0xe000 0x100>;
#phy-cells = <0>;
};
usb@fe800000 {
compatible = "snps,dwc3";
reg = <0xfe800000 0x10000>;
interrupts = <0 72 4>;
phys = <&usb_phy>;
phy-names = "usb3-phy";
status = "okay";
};
};
};
&label 引用并覆盖 status、pinctrl 等属性,实现“SoC 通用 + 板级定制”的分离。
3.4 设备树与 USB PHY 的绑定关系
USB PHY 是物理层收发器,负责将数字信号转换为模拟信号。设备树通过 phys 和 phy-names 属性将 USB 控制器与 PHY 绑定。
usb@fe800000 {
phys = <&usb_phy0 &usb_phy1>; // 引用多个 PHY
phy-names = "usb2-phy", "usb3-phy"; // 命名以便驱动区分
};
| 属性 | 作用 | 示例 |
|---|---|---|
phys |
PHY 节点引用列表 | <&usb_phy0 &usb_phy1> |
phy-names |
PHY 名称列表,与 phys 一一对应 | "usb2-phy", "usb3-phy" |
#phy-cells |
PHY 节点中定义的参数数量 | 0(无参数)或 1(如指定 PHY 类型) |
3.5 设备树编译与反编译
设备树源文件(.dts)需要编译为二进制设备树 blob(.dtb),内核在启动时解析 .dtb 文件。
# 编译 .dts 为 .dtb
dtc -I dts -O dtb -o am335x-board.dtb am335x-board.dts
# 反编译 .dtb 为 .dts
dtc -I dtb -O dts -o am335x-board.dts am335x-board.dtb
# 查看设备树内容
fdtdump am335x-board.dtb
address-cells 与 reg 字段数不匹配会导致地址解析错误。
3.6 设备树节点与属性关系图
下图展示了 USB 控制器节点、PHY 节点以及标准属性之间的引用关系:
3.7 实战:解析一个 USB 设备树片段
以下是一个真实的 USB 3.0 控制器设备树片段,结合本节所学知识逐行解析:
&usb3_0: usb@f010000 {
compatible = "snps,dwc3";
reg = <0x0f010000 0x10000>;
interrupts = <0 64 4>;
phys = <&usb_phy0>;
phy-names = "usb3-phy";
maximum-speed = "super-speed";
dr_mode = "host";
status = "okay";
};
| 属性 | 值 | 解析 |
|---|---|---|
compatible |
"snps,dwc3" |
匹配 Synopsys DWC3 USB 3.0 控制器驱动 |
reg |
<0x0f010000 0x10000> |
寄存器基址 0x0f010000,映射长度 64KB |
interrupts |
<0 64 4> |
SPI 中断,中断号 64,高电平触发 |
phys |
<&usb_phy0> |
引用 usb_phy0 节点作为 PHY |
phy-names |
"usb3-phy" |
该 PHY 的名称为 usb3-phy |
maximum-speed |
"super-speed" |
限制最高速度为 USB 3.0 SuperSpeed |
dr_mode |
"host" |
强制工作在 Host 模式 |
status |
"okay" |
设备启用 |
of_property_read_u32() 读取 reg,通过 of_parse_phandle() 解析 phys 引用。理解设备树就是理解驱动与硬件之间的“数据契约”。
3.8 本章小结
- 设备树语法:树形结构,节点表示设备,属性描述特性。
- 标准属性:
compatible(驱动匹配)、reg(地址映射)、interrupts(中断配置)、status(启用控制)、phandle(节点引用)。 - USB 绑定:通过
phys和phy-names将 USB 控制器与 PHY 设备关联。 - 编译工具:使用
dtc编译/反编译设备树,fdtdump查看二进制内容。