4. 根节点与模型:根节点(/)定义、model属性、compatible属性、版本信息
设备树的根节点是整个硬件描述树的起点,使用斜杠 / 表示。所有其他节点(如 CPU、内存、外设总线)都是根节点的子节点或后代节点。根节点本身也包含若干关键属性,用于描述整个设备的模型、兼容性以及设备树版本信息。
4.1 根节点的定义与结构
在 DTS 文件中,根节点通常位于文件的最顶层,其定义方式如下:
/ {
model = "TI AM335x BeagleBone Black";
compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
#address-cells = <1>;
#size-cells = <1>;
chosen { };
memory@80000000 { };
cpus { };
ocp { };
};
根节点必须包含 model 和 compatible 属性,这是设备树规范的基本要求。此外,#address-cells 和 #size-cells 用于定义子节点中地址和长度字段的宽度(以 32 位字为单位)。
关键点: 根节点没有
reg 属性,因为它代表整个系统,而不是一个可寻址的设备。根节点的 #address-cells 和 #size-cells 会被所有子节点继承,除非子节点重新定义。
4.2 model 属性:设备型号标识
model 属性是一个字符串,用于精确标识硬件平台的型号名称。它通常包含制造商名称和产品型号,格式为 "制造商,产品型号"。
| 属性 | 格式 | 示例 | 说明 |
|---|---|---|---|
model |
字符串 | "TI AM335x BeagleBone Black" |
人类可读的设备型号名称,用于识别具体硬件版本 |
compatible |
字符串列表 | "ti,am335x-bone-black", "ti,am33xx" |
用于操作系统匹配驱动,按从具体到通用的顺序排列 |
model 属性的主要用途:
- 调试与日志:内核启动时打印 model 字符串,帮助开发者确认当前运行的硬件平台。
- 用户空间识别:通过
/proc/device-tree/model文件读取,用户态程序可据此判断硬件类型。 - 固件与引导加载程序:U-Boot 等引导程序可根据 model 选择不同的设备树覆盖或配置。
4.3 compatible 属性:操作系统匹配的核心
compatible 属性是设备树中最重要的属性之一,它定义了设备与操作系统驱动之间的匹配关系。该属性是一个字符串列表,每个字符串代表一个兼容的设备型号,按从最具体到最通用的顺序排列。
compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
匹配规则:
- 操作系统(如 Linux 内核)在启动时读取根节点的
compatible属性。 - 内核遍历字符串列表,依次尝试与注册的
DT_MACHINE或of_device_id匹配。 - 匹配成功则加载对应的板级初始化代码或设备驱动。
- 如果所有字符串都匹配失败,内核可能无法正确初始化该平台。
实践建议: 编写根节点的
compatible 时,务必包含从具体型号到通用 SoC 系列的完整链条。例如,对于 BeagleBone Black,应包含板级型号 "ti,am335x-bone-black"、板级系列 "ti,am335x-bone" 和 SoC 系列 "ti,am33xx"。这样即使未来内核移除了对特定板级的支持,仍能通过通用 SoC 匹配项保持兼容。
4.4 版本信息与设备树版本
设备树本身也有版本概念,主要通过以下方式体现:
| 版本信息类型 | 表示方式 | 说明 |
|---|---|---|
| DTS 文件版本 | 文件头注释或版本控制 | 通过 Git 等版本管理工具追踪 DTS 文件的修改历史 |
| 设备树规范版本 | DTB 头部字段 | 编译后的 DTB 文件头部包含版本号字段,用于解析器兼容性检查 |
| 板级版本 | model 属性 |
通过 model 字符串区分同一产品的不同硬件版本(如 Rev B vs Rev C) |
| 兼容性版本 | compatible 属性 |
通过字符串列表表达硬件兼容性层级,隐含版本演进关系 |
在 DTB 文件头部,设备树编译器会写入以下版本相关字段:
- boot_param_header 版本:标识 DTB 头部结构的版本号,目前通常为 17。
- totalsize:DTB 文件总大小,用于解析器分配内存。
- off_dt_struct 和 off_dt_strings:指向设备树结构和字符串块的偏移量。
注意: 不要将设备树版本与 Linux 内核版本混淆。同一份 DTS 文件可以用于多个内核版本,但需要确保内核中的设备树解析器版本与 DTB 版本兼容。通常,使用较新版本的 dtc 编译器生成的 DTB 可以向后兼容旧内核。
4.5 根节点结构图
下图展示了根节点及其核心属性的层次关系,以及它们如何与操作系统交互:
4.6 根节点属性对比表
下表总结了根节点中常见属性的用途、格式和注意事项:
| 属性名 | 是否必需 | 格式 | 用途 | 注意事项 |
|---|---|---|---|---|
model |
是 | 字符串 | 标识硬件平台型号 | 应包含制造商和产品名,如 "TI AM335x BeagleBone Black" |
compatible |
是 | 字符串列表 | 操作系统驱动匹配 | 按从具体到通用排序,至少包含一个 SoC 级兼容项 |
#address-cells |
推荐 | 32 位整数 | 定义子节点地址字段的 32 位字数量 | 通常为 1(32 位地址)或 2(64 位地址) |
#size-cells |
推荐 | 32 位整数 | 定义子节点长度字段的 32 位字数量 | 通常为 1(32 位长度)或 2(64 位长度) |
chosen |
否 | 子节点 | 传递引导参数(如 bootargs、stdout-path) | 由引导加载程序填充,DTS 中可定义默认值 |
aliases |
否 | 子节点 | 为节点定义别名,方便引用 | 别名必须是唯一的,且不能包含特殊字符 |
4.7 实践案例:编写根节点
假设我们要为一块基于 NXP i.MX6ULL 的工控板编写根节点,硬件信息如下:
- 板级型号:
MYD-Y6ULL-14x14 - SoC 系列:
fsl,imx6ull - 内存地址空间:32 位
- 引导控制台:串口 1
对应的根节点定义如下:
/ {
model = "MYiR MYD-Y6ULL-14x14 Board";
compatible = "myir,myd-y6ull-14x14", "fsl,imx6ull";
#address-cells = <1>;
#size-cells = <1>;
chosen {
stdout-path = &uart1;
bootargs = "console=ttymxc0,115200 root=/dev/mmcblk0p2 rootwait";
};
aliases {
mmc0 = &usdhc1;
mmc1 = &usdhc2;
serial0 = &uart1;
};
memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x20000000>; /* 512 MB */
};
};
关键实践要点:
compatible的第一项必须是当前板级的具体型号,第二项是 SoC 系列,便于内核回退匹配。model字符串应包含制造商和完整产品名,方便调试时快速识别。chosen节点中的stdout-path指定内核启动日志输出设备,通常指向调试串口。aliases节点为常用外设(如 MMC、串口)定义简短别名,便于其他节点引用。memory节点必须包含device_type = "memory"属性,这是设备树规范的要求。
4.8 常见错误与排查
| 错误类型 | 现象 | 原因 | 解决方案 |
|---|---|---|---|
缺少 model 属性 |
内核启动时显示 No model name in device tree |
根节点未定义 model 属性 | 添加 model = "xxx"; |
compatible 顺序错误 |
内核无法匹配到正确的板级初始化代码 | 通用项放在了具体项之前 | 将最具体的板级型号放在列表首位 |
#address-cells 缺失 |
子节点 reg 属性解析错误,内存映射异常 | 根节点未定义地址单元大小 | 根据 SoC 地址宽度添加 #address-cells |
chosen 节点拼写错误 |
内核启动参数不生效 | 节点名写成了 choose 或 chossen |
检查节点名必须为 chosen |
调试提示: 如果内核启动时出现
OF: fdt: not found /model 或 No compatible manufacturer found 等错误,请首先检查根节点的 model 和 compatible 属性是否正确定义。可以使用 dtc -I dtb -O dts xxx.dtb 反编译 DTB 文件,直接查看根节点内容。