第四节:设备树绑定文档——如何阅读内核Documentation/devicetree/bindings/下的文档
说实话,我刚接触设备树那会儿,最头疼的就是看绑定文档。内核里那一堆 .txt 和 .yaml 文件,密密麻麻的,看着就头大。但后来我发现,这些文档其实是咱们调试设备树时最靠谱的“参考答案”。
今天我就带你捋一捋,怎么高效地啃下这些绑定文档。
4.1 绑定文档到底长啥样?
内核的绑定文档放在 Documentation/devicetree/bindings/ 目录下。按厂商和子系统分门别类。比如你要找 I2C 控制器的绑定,就去 i2c/ 下面找;要找某款 GPIO 芯片的,就去 gpio/ 里翻。
文档格式主要有两种:
- 传统 .txt 格式:老牌驱动用的多,纯文本描述,结构自由但容易写得乱。
- 现代 .yaml 格式:新驱动基本都转成 YAML 了,用
dt-schema工具可以自动校验,规范很多。
我个人习惯先看 YAML 格式的,因为它结构清晰,一眼就能看到 required 属性和各个字段的类型。
4.2 抓住文档里的“骨架”
不管什么格式,绑定文档的核心信息就这几块:
| 信息块 | 说明 |
|---|---|
| compatible 字符串 | 这是设备树匹配驱动的“钥匙”。比如 "ti,omap3-i2c",前面是厂商,后面是设备名。 |
| required 属性 | 必须写的属性,少一个驱动就可能不 probe。比如 reg、interrupts 这些。 |
| optional 属性 | 可选的,比如时钟频率、电源域等。不写就用驱动默认值。 |
| 子节点描述 | 有些设备(比如 I2C 控制器)下面要挂子设备,文档会说明子节点怎么写。 |
| 例子 | 最实用的部分!直接抄过来改改就能用。 |
嗯,这里要注意:compatible 字符串一定要一字不差。大小写、下划线、逗号,错一个驱动就认不出来。我曾经因为把 "fsl,imx6q-uart" 写成了 "fsl,imx6q-uart "(多了个空格),排查了整整一下午。
4.3 怎么读 YAML 格式的绑定文档?
YAML 文档看起来像这样:
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/i2c/i2c-imx.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale i.MX I2C Controller
maintainers:
- Oleksij Rempel <o.rempel@pengutronix.de>
properties:
compatible:
oneOf:
- items:
- enum:
- fsl,imx1-i2c
- fsl,imx21-i2c
- const: fsl,imx1-i2c
reg:
maxItems: 1
interrupts:
maxItems: 1
required:
- compatible
- reg
- interrupts
additionalProperties: false
examples:
- |
i2c@43f8000 {
compatible = "fsl,imx21-i2c", "fsl,imx1-i2c";
reg = <0x43f8000 0x4000>;
interrupts = <10>;
clock-frequency = <100000>;
};
你看,YAML 把属性类型、是否必须、取值范围都写得很清楚。我一般先看 required 部分,把必须的属性列出来,然后去设备树里核对。再看 examples,直接复制出来改地址和中断号,基本不会出错。
4.4 读 .txt 文档的“土办法”
老式的 .txt 文档没有 YAML 那么规整,但核心信息都在。我总结了一个阅读顺序:
- 先看开头几行:通常第一段就告诉你这个设备是干嘛的,compatible 字符串是什么。
- 找 Required properties:文档里一般会用
- required或者加粗标出来。没有的话就找compatible、reg、interrupts这些常见属性。 - 看 Optional properties:这里经常藏着一些“彩蛋”,比如某个厂商特有的配置项。
- 翻到最下面找例子:.txt 文档的例子通常放在末尾,有时候还会带一段 dts 片段。
举个例子,Documentation/devicetree/bindings/i2c/i2c-omap.txt 里这样写:
Required properties:
- compatible: Should be "ti,omap3-i2c" for OMAP3 devices
- reg: Physical base address of the controller and length
- interrupts: Interrupt number for the controller
Optional properties:
- clock-frequency: Desired I2C bus frequency in Hz
- ti,hwmods: Name of the hwmod associated with the I2C controller
Example:
i2c@48072000 {
compatible = "ti,omap3-i2c";
reg = <0x48072000 0x1000>;
interrupts = <56>;
clock-frequency = <400000>;
};
说白了,就是照着这个模板填你的硬件参数。地址、中断号去芯片手册里查,时钟频率按实际需求写。
4.5 避坑指南:我踩过的那些雷
有些文档要求 compatible 是 "厂商,设备",有些要求是 "具体型号,通用型号"。比如 "fsl,imx21-i2c", "fsl,imx1-i2c",前面的更具体,后面的更通用。驱动匹配时从前往后试,顺序错了可能匹配不到。
reg 属性由地址和长度组成。比如 reg = <0x43f8000 0x4000>,长度 0x4000 表示寄存器空间大小。我见过有人把长度写成 0x4,结果驱动访问寄存器时直接访问到别的设备地址上去了。
拿到一个新板子,我会先找到对应 SoC 的绑定文档,把 required 属性列个清单。然后对照原理图,把每个外设的地址、中断号、时钟都填进去。这样写出来的设备树,基本一次就能跑起来。
4.6 怎么验证你写的设备树对不对?
光看文档还不够,你得动手验证。内核提供了几个工具:
- dtc 编译:
dtc -I dts -O dtb -o test.dtb test.dts,编译时就能发现语法错误。 - dt-validate:配合 YAML 绑定文档,可以检查属性是否合规。命令是
dt-validate -s /path/to/schemas test.dtb。 - 内核启动日志:启动时加
earlycon和dtbdump参数,内核会打印设备树解析过程中的错误信息。
我个人的工作流是这样的:写完设备树 → dtc 编译 → dt-validate 校验 → 烧录启动 → 看 dmesg 有没有 OF: fdt: 开头的错误。如果一切顺利,驱动就会乖乖地 probe 成功。
4.7 总结一下
读绑定文档其实没那么玄乎。你只要抓住三点:
- compatible 字符串:驱动匹配的关键,一个字都不能错。
- required 属性:缺一不可,少了驱动就不干活。
- 例子:最好的老师,直接抄过来改参数。
下次你调试设备树遇到问题,别急着瞎改。先翻翻对应的绑定文档,对照着检查一遍,八成问题就找到了。嗯,这招我用了好多年,屡试不爽。