设备树(Device Tree)说明
本文面向软件工程师,讲清三件事:本 SDK 的设备树分几层、怎么拼起来、怎么改。看完就能自己改引脚、增删节点、给新外设加设备树,不用再”猜”。
一、为什么要有设备树
Linux 内核不再把板级硬件信息写死在代码里,而是由一份 设备树(.dts/.dtb) 描述:有几个串口、每个引脚什么复用、挂的芯片地址是多少、屏幕时序多少。内核启动时读取它。
所以改硬件(换屏、改引脚、接新芯片)时,大多数情况只改设备树,不用动驱动代码。
二、本 SDK 的设备树分三层
| 层 | 文件 | 作用 |
|---|---|---|
| 基础层 | device/config/chips/t153/configs/t153_nand_base/linux-5.10-origin/board-base.dtsi |
SoC 与板子的通用节点:pwm2、uart0/3/8、twi2、gmac0/1、csi、nand 等,默认使能状态在这里定义 |
| 型号层 | BoardConfig/BoardType/ypt153evb-board.dts |
本型号的差异:屏使能、触摸/网口 PHY/音频引脚、摄像头引脚、时钟,以及对基础层节点的覆盖 |
| U-Boot 层 | BoardConfig/uboot_dts/ypt153evb-board.dts |
U-Boot 自己的设备树(含 LT8912B HDMI 桥等),与内核 DT 分开编译 |
编译时,基础层 + 型号层会 merge 成最终 DTB(out/.../sun8iw22p1-*.dtb),U-Boot 用自己那份。
记忆口诀:通用能力在
board-base.dtsi,本板差异在BoardType/xxx.dts,引导阶段在uboot_dts/xxx.dts。
三、设备树语法速览(够用版)
&twi2 { // &节点标签:引用已存在的节点(追加/覆盖属性)
clock-frequency = <100000>;
status = "okay"; // 开关:okay 使能 / disabled 关闭
es8388: es8388@11 { // 子节点:@后面是 I2C 地址
compatible = "everest,es8323"; // 匹配驱动的名字
reg = <0x11>; // 寄存器地址(I2C 从机地址)
};
};四个高频概念:
| 概念 | 含义 | 例子 |
|---|---|---|
compatible |
驱动匹配字符串 | "everest,es8323" |
reg |
地址(I2C 从机地址 / 内存地址) | <0x11> |
status |
使能开关 | "okay" / "disabled" |
pinctrl-0 |
绑定引脚复用配置 | <&uart0_pins_active> |
| phandle | 用 &标签 引用别的节点 |
<&pio PA 20 ...> |
四、怎么看当前运行中的设备树
开发板上(无需源码):
# 内核已解析的实时设备树
ls /proc/device-tree/
cat /proc/device-tree/model
# 等价位置(新版内核)
ls /sys/firmware/devicetree/base想看二分制 DTB 反编译成文本:
dtc -I dtb -O dts -o board.dts out/.../sun8iw22p1-ypt153evb.dtb # SDK 主机上五、怎么改引脚(pinctrl)——以串口为例
引脚复用写在 pinctrl 子节点里,uart0 的引脚定义(基础层):
uart0_pins_active: uart0@0 {
pins = "PB9", "PB10"; // 引脚
function = "uart0"; // 复用功能名
drive-strength = <10>;
};然后节点引用它:
&uart0 {
pinctrl-0 = <&uart0_pins_active>; // 使用上面这组引脚
status = "okay";
};改引脚三步:
- 找到/新建
xxx_pins_active节点,改pins和function; - 让外设节点
pinctrl-0指向它; - 编译 + 上板
cat /proc/device-tree/...验证。
六、怎么增 / 删 / 启用节点
- 启用:把
status改成"okay"(如&uart2 { status = "okay"; };)。 - 关闭:
status = "disabled";(板级 dts 里大量这么关掉不用的串口)。 - 新增:在
&twi2下加子节点(如上文的es8388@11),写好compatible/reg即可。 - 覆盖:在型号层写
&节点 { 属性 = 新值; };,后加载的覆盖先加载的。
七、本板各外设真实设备树节点(汇总)
1) PWM 与背光(board-base.dtsi)
backlight0: backlight0 {
compatible = "pwm-backlight";
status = "okay";
default-brightness-level = <180>;
enable-gpios = <&pio PD 22 GPIO_ACTIVE_HIGH>; // 背光使能
pwms = <&pwm2 7 25000 1>; // 通道7,40kHz
};
&pwm2 { status = "okay"; };
&pwm2_7 { pinctrl-0 = <&pwm2_7_pins_active>; status = "okay"; };
pwm2_7_pins_active: pwm2_7@0 { pins = "PD23"; function = "pwm2_7"; };2) 串口(board-base.dtsi + 型号层)
&uart0 { pinctrl-0 = <&uart0_pins_active>; status = "okay"; }; // PB9/PB10 调试
&uart3 { status = "okay"; }; // PK6/PK9/PK10/PK11
&uart8 { status = "okay"; }; // PB4/PB5
// 型号层把 uart1/2/4/5/6/7/9 置 disabled3) I2C2 上的三颗芯片(型号层 &twi2)
&twi2 {
clock-frequency = <100000>;
status = "okay";
pcf8563: rtc@51 { compatible = "nxp,pcf8563"; reg = <0x51>; };
gt9xx: gt9xx@5d { compatible = "goodix,gt9xx"; reg = <0x5d>;
reset-gpios = <&pio PA 21 GPIO_ACTIVE_LOW>;
irq-gpios = <&pio PA 22 GPIO_ACTIVE_LOW>; };
es8388: es8388@11 { compatible = "everest,es8323"; reg = <0x11>; };
};4) 双网口(型号层)
&gmac0 { phy-mode = "rgmii"; phy-handle = <&gmac0_phy0>; tx-delay = <5>; rx-delay = <5>; status = "okay"; };
&gmac1 { phy-mode = "rgmii"; phy-handle = <&gmac1_phy0>; tx-delay = <5>; rx-delay = <5>; status = "okay"; };
&mdio0 { gmac0_phy0: ethernet-phy@0 { compatible = "ethernet-phy-ieee802.3-c22","jl2101b"; reg = <0x0>; reset-gpios = <&pio PG 5 GPIO_ACTIVE_LOW>; }; };
&mdio1 { gmac1_phy0: ethernet-phy@1 { compatible = "ethernet-phy-ieee802.3-c22","jl2101b"; reg = <0x1>; reset-gpios = <&pio PJ 6 GPIO_ACTIVE_LOW>; }; };5) 双模显示(型号层)
&rgb_panel0 { status = "okay"; enable0-gpios = <&pio PA 20 GPIO_ACTIVE_LOW>;
display-timings { /* 1024x600,clock 61470000 */ }; };
&panel_0 { status = "disabled"; display-timings { /* 1920x1080,clock 148500000 */ }; };
&dsi0 { status = "disabled"; };
// U-Boot 启动时读 env(display_mode),用 fdt set 覆盖,此处是默认值6) 摄像头与 CAN(型号层 / 基础层)
mipi_csi1_pins_a: mipi_csi1@0 { pins = "PK0","PK1","PK2","PK3","PK4","PK5"; function = "mcsia"; };
ncsi_8bit_pins_a: ncsi_8bit@0 { pins = "PA7","PA4","PA5","PA8","PA9","PA10","PA11","PA12","PA13","PA14","PA15"; function = "ncsi"; };
can1 { status = "disabled"; }; // CAN 出厂关闭八、改完怎么编译与验证
./yz_build.sh config # 选 t153_nand_base
./yz_build.sh kernel # 只编内核(含新 DTB)
./yz_build.sh pack # 打包固件
# 或整包
./yz_build.sh all验证:
- 主机:
dtc -I dtb -O dts out/.../xxx.dtb | less看是否已改。 - 板上:
cat /proc/device-tree/.../status、ls /sys/class/pwm、ls /dev/ttyAS*、i2cdetect -l。
九、常见错误
| 现象 | 原因 / 处理 |
|---|---|
| 改完没生效 | 只编了 kernel 没重打 pack;或改错层(改到 U-Boot 层而内核不读) |
| 引脚无输出 | pinctrl-0 没指向新 pin 节点;或引脚被别的节点占用 |
| I2C 设备找不到 | reg 地址写错;status 不是 okay;&twi2 本身没 okay |
编译报错 Phandle ... not found |
引用的标签(&xxx)不存在或拼错 |
| 屏黑 | enable0-gpios 极性与实际相反;display-timings 时钟算错 |
十、小结
- 通用能力在
board-base.dtsi,本板差异在BoardType/ypt153evb-board.dts,引导在uboot_dts/; - 改引脚改
pinctrl,启用/关闭改status,加芯片在总线节点下加子节点; - 改完
./yz_build.sh kernel && ./yz_build.sh pack,用/proc/device-tree或dtc验证。
具体每个外设怎么用,见「外设驱动」目录各篇;每篇末尾也都附了对应的真实设备树片段。
作者:Mai 创建时间:2026-10-20 16:46
最后编辑:Mai 更新时间:2026-11-05 14:56
最后编辑:Mai 更新时间:2026-11-05 14:56