设备树故障处理案例
案例 1:驱动 probe 未被调用
排查:
bash
# 1. 确认设备树节点存在
ls /sys/firmware/devicetree/base/soc/
# 2. 检查 compatible 是否匹配
cat /sys/firmware/devicetree/base/soc/serial@fe201000/compatible
# 3. 检查 status
cat /sys/firmware/devicetree/base/soc/serial@fe201000/status
# 必须是 "okay" 或 "ok"
# 4. 查看 platform 设备列表
ls /sys/bus/platform/devices/ | grep fe201000
# 5. 查看驱动匹配情况
ls /sys/bus/platform/drivers/my-uart/常见原因:
| 原因 | 解决 |
|---|---|
status = "disabled" | 在板级 dts 中改为 "okay" |
| compatible 字符串拼写错误 | 逐字符对比 DTS 和 of_match_table |
| DTB 未更新 | 重新编译并烧录 DTB |
| 驱动模块未加载 | modprobe my-uart |
案例 2:reg 地址映射失败
现象:devm_ioremap_resource 返回 -EBUSY 或 -EINVAL。
排查:
bash
# 查看 iomem 分配情况
cat /proc/iomem | grep fe201000
# 检查 DTS 中 reg 格式
dtc -I fs /sys/firmware/devicetree/base | grep -A5 "serial@fe201000"常见原因:
c
/* ❌ 错误:#address-cells=<1> 但写了 64 位地址 */
soc {
#address-cells = <1>;
uart@fe201000 {
reg = <0x0 0xfe201000 0x0 0x1000>; /* 4 个 cell,但父节点期望 2 个 */
};
};
/* ✅ 正确 */
soc {
#address-cells = <1>;
#size-cells = <1>;
uart@fe201000 {
reg = <0xfe201000 0x1000>;
};
};案例 3:中断号获取失败
现象:platform_get_irq() 返回负值。
排查:
bash
# 查看中断属性
cat /sys/firmware/devicetree/base/soc/serial@fe201000/interrupts | xxd
# 查看 interrupt-parent
cat /sys/firmware/devicetree/base/soc/serial@fe201000/interrupt-parent | xxd常见原因:
c
/* ❌ 错误:GIC SPI 中断号从 0 开始,但硬件手册从 32 开始 */
/* 硬件手册说 IRQ 64,DTS 中应写 64-32=32 */
interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>; /* 错误 */
interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>; /* 正确 */
/* ❌ 错误:缺少 interrupt-parent */
/* 如果节点不在 GIC 的子树下,需要显式指定 */
interrupt-parent = <&gic>;
interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;案例 4:时钟获取失败
现象:devm_clk_get() 返回 -ENOENT。
bash
# 查看时钟属性
cat /sys/firmware/devicetree/base/soc/serial@fe201000/clock-names常见原因:
c
/* ❌ clock-names 与驱动中请求的名称不一致 */
/* DTS */
clock-names = "pclk"; /* 写的是 pclk */
/* 驱动 */
clk = devm_clk_get(dev, "uart_clk"); /* 请求的是 uart_clk */
/* ✅ 保持一致 */
clock-names = "uart_clk";案例 5:GPIO 获取失败
现象:devm_gpiod_get() 返回 -ENOENT 或 -EPROBE_DEFER。
c
/* ❌ 属性名不符合规范 */
my-gpio = <&gpio 10 GPIO_ACTIVE_LOW>;
/* 驱动中 */
gpiod_get(dev, "my", GPIOD_OUT_LOW); /* 会查找 "my-gpios" 属性 */
/* ✅ 属性名必须以 -gpios 结尾(单个也可用 -gpio) */
reset-gpios = <&gpio 10 GPIO_ACTIVE_LOW>;
/* 驱动中 */
gpiod_get(dev, "reset", GPIOD_OUT_LOW); /* 查找 "reset-gpios" */案例 6:DTB 与内核版本不匹配
现象:启动时出现 OF: fdt: No chosen node found 或设备无法识别。
bash
# 检查 DTB 版本信息
fdtget /boot/dtb/myboard.dtb / model
# 重新编译 DTB(在内核源码目录)
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- dtbs
# 生成在 arch/arm64/boot/dts/myvendor/myboard.dtb