2. Linux 设备树基础:语法、节点与属性
设备树(Device Tree)是嵌入式 Linux 系统中描述硬件拓扑与资源分配的核心机制。对于蓝牙串口驱动而言,设备树负责向内核传递 UART 控制器地址、中断号、时钟频率、DMA 通道以及蓝牙电源控制 GPIO 等关键参数。本章从语法、节点结构、文件组织与编译工具四个维度展开,为后续蓝牙串口设备树配置奠定基础。
2.1 设备树语法基础
设备树源文件(.dts)采用层次化的键值对语法,每个节点代表一个硬件设备或总线,属性描述设备的特性。基本语法规则如下:
- 节点定义:
node-name@unit-address,其中unit-address通常为寄存器基址。 - 属性赋值:
property-name = <value>;,支持 32 位整数、字符串、字节数组、phandle引用。 - 标签(label):为节点起别名,便于引用,如
uart0: serial@fe201000。 - 包含文件:
#include "soc.dtsi",复用 SoC 级定义。
/dts-v1/;
/ {
model = "Bluetooth UART Board";
compatible = "vendor,bt-board";
chosen {
stdout-path = &uart0;
};
uart0: serial@fe201000 {
compatible = "vendor,bluetooth-uart";
reg = <0xfe201000 0x1000>;
interrupts = <0 33 4>;
clocks = <&clk_uart0>;
bluetooth-gpios = <&gpio1 12 GPIO_ACTIVE_HIGH>;
status = "okay";
};
};
上述示例中,uart0 节点描述了蓝牙串口控制器的寄存器地址、中断号、时钟源以及蓝牙使能 GPIO。驱动通过 of_match_table 匹配 compatible 字符串来获取这些属性。
2.2 节点与属性详解
设备树中的节点和属性是驱动获取硬件信息的唯一入口。下表列出蓝牙串口驱动最常用的节点属性及其含义:
| 属性名 | 格式 | 蓝牙串口驱动用途 |
|---|---|---|
compatible |
字符串 | 驱动匹配标识,如 "brcm,bcm43438-uart" |
reg |
<地址 长度> | UART 控制器寄存器基址与映射范围 |
interrupts |
<类型 编号 触发> | UART 中断号与触发方式(边沿/电平) |
clocks |
phandle | UART 模块时钟源引用 |
bluetooth-gpios |
phandle + 标志 | 蓝牙芯片使能/复位 GPIO |
max-speed |
整数 | 蓝牙串口最高波特率(如 4000000) |
status |
字符串 | 设备启用状态:"okay" / "disabled" |
bluetooth-gpios 属性中指定 GPIO 标志(如 GPIO_ACTIVE_HIGH),导致蓝牙模块无法正确上电复位。务必在 dtsi 或 dts 头部 #include <dt-bindings/gpio/gpio.h>。
2.3 dts / dtsi 文件结构
设备树源文件分为两类:.dtsi(包含文件)和 .dts(板级文件)。.dtsi 存放 SoC 级通用定义,.dts 存放具体板卡的差异化配置。这种分离设计提高了复用性。
// soc.dtsi — SoC 级通用定义
/ {
soc {
uart0: serial@fe201000 {
compatible = "vendor,uart-ip";
reg = <0xfe201000 0x1000>;
interrupts = <0 33 4>;
clocks = <&clk_uart0>;
status = "disabled"; // 默认关闭
};
};
};
// board.dts — 板级配置
/dts-v1/;
#include "soc.dtsi"
#include <dt-bindings/gpio/gpio.h>
&uart0 {
status = "okay";
pinctrl-0 = <&uart0_pins>;
bluetooth-gpios = <&gpio1 12 GPIO_ACTIVE_HIGH>;
max-speed = <4000000>;
};
上述代码中,board.dts 通过 &uart0 引用 soc.dtsi 中定义的节点,并覆盖 status、添加蓝牙专用属性。这种“引用 + 覆盖”机制是设备树配置的核心模式。
2.4 编译与反编译
设备树编译器(dtc)将可读的 .dts 源文件编译为二进制 .dtb(Device Tree Blob),供内核在启动时解析。反编译则用于调试和逆向分析现有 .dtb 文件。
| 操作 | 命令 | 说明 |
|---|---|---|
| 编译 | dtc -I dts -O dtb -o board.dtb board.dts |
将 .dts 编译为 .dtb |
| 反编译 | dtc -I dtb -O dts -o board.dts board.dtb |
将 .dtb 反编译为 .dts |
| 检查 | dtc -I dtb -O dts /sys/firmware/fdt |
查看当前系统使用的设备树 |
| 验证 | dtc -I dts -O dtb board.dts >/dev/null |
仅检查语法错误,不输出文件 |
dtc -I dtb -O dts /sys/firmware/fdt 可导出当前内核使用的完整设备树,用于确认蓝牙节点是否被正确加载。若节点 status 为 "disabled",驱动将不会 probe。
编译时,dtc 会递归展开所有 #include 文件,并解析 /include/ 指令。最终生成的 .dtb 是扁平的二进制结构,包含所有节点、属性以及字符串表。内核启动时,bootloader 将 .dtb 加载到内存,并将地址传递给内核。
2.5 蓝牙串口设备树配置要点
针对蓝牙串口驱动,设备树配置需额外关注以下要点:
- pinctrl 引脚复用:确保 UART TX/RX/CTS/RTS 引脚被正确配置为外设功能,而非 GPIO。
- 蓝牙电源管理:通过
bluetooth-gpios或vbat-supply属性控制蓝牙模块的电源与复位时序。 - 波特率约束:部分蓝牙芯片(如 BCM43438)要求最高 4Mbps,需在
max-speed中明确指定。 - DMA 支持:若使用 DMA 传输,需添加
dmas和dma-names属性,并确保 DMA 控制器节点已使能。
bluetooth-gpios、max-speed)放在板级 .dts 中,而非 SoC 级 .dtsi。这样当蓝牙模块更换时,只需修改板级文件,不影响 SoC 通用定义。