设备树:原理与语法
什么是设备树
设备树(Device Tree)是描述硬件拓扑的数据结构,以文本格式(DTS)编写,编译为二进制(DTB)后由 Bootloader 传递给内核。它解决了 ARM 平台"板级代码爆炸"问题——同一内核镜像可以通过不同 DTB 支持不同硬件。
DTS 源文件 (.dts / .dtsi)
│ dtc 编译器
▼
DTB 二进制 (.dtb)
│ Bootloader 加载
▼
内核解析 → 创建 platform_device / i2c_client 等DTS 基本语法
c
/dts-v1/;
/ { /* 根节点 */
#address-cells = <1>; /* 子节点 reg 地址占 1 个 cell */
#size-cells = <1>; /* 子节点 reg 大小占 1 个 cell */
model = "My Board v1.0";
compatible = "myvendor,myboard";
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
compatible = "arm,cortex-a53";
reg = <0>; /* CPU 编号 */
};
};
memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x40000000>; /* 基地址 + 大小 */
};
soc {
#address-cells = <1>;
#size-cells = <1>;
ranges; /* 地址透传 */
uart0: serial@fe201000 {
compatible = "myvendor,my-uart";
reg = <0xfe201000 0x1000>;
interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&ccu CLK_UART0>;
clock-names = "uart_clk";
pinctrl-0 = <&uart0_pins>;
pinctrl-names = "default";
status = "disabled"; /* 默认禁用 */
};
i2c0: i2c@fe804000 {
compatible = "myvendor,my-i2c";
reg = <0xfe804000 0x1000>;
interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
status = "okay";
/* I2C 从设备 */
eeprom@50 {
compatible = "atmel,24c256";
reg = <0x50>;
pagesize = <64>;
};
};
};
};板级文件覆盖(.dts 引用 .dtsi)
c
/* SoC 级描述:my-soc.dtsi */
/ {
soc {
uart0: serial@fe201000 {
compatible = "myvendor,my-uart";
reg = <0xfe201000 0x1000>;
status = "disabled"; /* SoC 级默认禁用 */
};
};
};
/* 板级描述:myboard.dts */
#include "my-soc.dtsi"
&uart0 {
status = "okay"; /* 板级启用 */
current-speed = <115200>;
};常用属性速查
compatible
驱动匹配的关键属性,格式为 "vendor,device":
c
compatible = "myvendor,my-uart-v2", "myvendor,my-uart";
/* 内核从左到右尝试匹配,支持向后兼容 */reg
设备寄存器地址和大小:
c
/* 单段 */
reg = <0xfe201000 0x1000>;
/* 多段(如 PCI BAR) */
reg = <0x0 0xfe201000 0x0 0x1000>,
<0x0 0xfe202000 0x0 0x1000>;interrupts
c
/* GIC SPI 中断 */
interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
/* 多个中断 */
interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 33 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "rx", "tx";驱动中按名称获取:
c
irq = platform_get_irq_byname(pdev, "rx");clocks
c
clocks = <&ccu CLK_UART0>, <&ccu CLK_APB>;
clock-names = "uart_clk", "apb_pclk";驱动中:
c
clk = devm_clk_get(&pdev->dev, "uart_clk");gpio
c
reset-gpios = <&gpio 10 GPIO_ACTIVE_LOW>;
enable-gpios = <&gpio 11 GPIO_ACTIVE_HIGH>;驱动中:
c
struct gpio_desc *reset = devm_gpiod_get(&pdev->dev, "reset", GPIOD_OUT_HIGH);
gpiod_set_value(reset, 1); /* 置高(考虑极性) */设备树 Overlay(动态加载)
c
/* my-sensor.dts overlay */
/dts-v1/;
/plugin/;
&i2c0 {
#address-cells = <1>;
#size-cells = <0>;
sensor@48 {
compatible = "ti,tmp102";
reg = <0x48>;
};
};bash
# 编译 overlay
dtc -@ -I dts -O dtb -o my-sensor.dtbo my-sensor.dts
# 加载 overlay(Raspberry Pi 风格)
dtoverlay my-sensor
# 或通过 configfs
mkdir /sys/kernel/config/device-tree/overlays/my-sensor
cat my-sensor.dtbo > /sys/kernel/config/device-tree/overlays/my-sensor/dtbo调试工具
bash
# 查看当前设备树
dtc -I fs /sys/firmware/devicetree/base
# 查看特定节点
cat /sys/firmware/devicetree/base/soc/serial@fe201000/compatible
# 反编译 DTB
dtc -I dtb -O dts -o out.dts /boot/dtb/myboard.dtb
# 查看内核解析结果
ls /sys/bus/platform/devices/