掌握设备树:Linux 中的硬件集成指导
嵌入式系统具有不同的部件和架构,需要一种高效的、规范的、可复用的描述硬件的方式。Linux Device Tree 提供了一种灵活的结构来解决这个问题,通过操作系统和bootloader能理解的方式来定义硬件细节。现在我们来讨论一下 Device Tree 是如何工作的、为什么它们很重要、它们是如何组织的。
一、可发现硬件 vs. 不可发现硬件
嵌入式平台中,并不是所有硬件都是可发现的。
- 可发现硬件:一些总线,如PCI(e) 和 USB,是支持设备发现功能的,意味着它们可以在运行时自动枚举并连接到这些总线上的设备。这些总线上的设备可以和系统传达厂商ID、产品ID和设备类型这些信息。
- 不可发现硬件:总线如 I2C,SPI 和 1线是缺乏可发现性的。此时,系统必须知道连接了哪些设备、它们是如何架构的。依赖这些总线的嵌入式系统中,Device Tree是特别有用的。
二、不可发现硬件的硬件描述
对于不可发现硬件,Device Tree 文件传达了硬件分布的关键信息,包括:
- CPU 核:例如,一个系统可能含有两个 Cortex-A9 核心
- 内存映射控制器:具体设备的细节,比如UART、I2C的内存地址和中断请求
- 板级部件:连接在具体SoC总线上的外设,比如音频编解码器,并提供它们的从设备地址、时钟源、复位信号
操作系统和bootloader不能不知道这些细节,使得Device Tree在硬件结构上非常重要。
三、描述不可发现硬件:Device Tree 是如何工作的
有三种处理不可发现硬件信息的方式:
- 直接写入 OS/Bootloader 代码中:一般,这是使用 C语言数据结构实现的,但这种方法可能在 ARM32 平台上难以维护
- ACPI 表:主要在 x86 系统和一些 ARM64平台上使用。固件会提供 OS能解释的ACPI 表
- Device Tree:大多数嵌入式 CPU架构采用,包括 ARM、RISC-V、MIPS 和 PowerPC。一开始是用于 PowerPC 的,Device Tree 现在被广泛的应用在多种平台上,包括 Linux、U-Boot 和 FreeBSD。一个 Device Tree file(DTB)在移植 Linux到新的硬件上时是必须的。
四、Device Tree 原理
Device Tree 由描述硬件的树形数据结构组成,一般写在 Device Tree Source(.dts)文件里,然后通过Device Tree 编译器编译成 Device Tree Blob(.dtb)形式。DTB形式是高效的、OS-无关的、灵活的:
- Bootloader 集成:DTB 可以直接链接到 bootloader内部,也可以由 bootloader 传递给 OS。
五、Device Tree 语法
Device Tree 使用节点和属性的层级结构:
- 节点:描述设备或IP块
- 属性:定义这些设备的特性
每一个节点可以通过phandle来引用其他节点,从而实现不同节点之间的互相引用。这种结构使得硬件描述模块化。
六、Device Tree 源文件在哪
尽管Device Tree 是OS-无关的,但是没有一个中央仓库来专门存放。Linux kernel 一般是这些文件的主要来源,大部分都在 arch/<ARCH>/boot/dts下。它们和其他项目如 U-Boot 和 Barebox 是同步的。
七、Device Tree 的继承和模块化
Device Tree通过 .dtsi文件(描述SoC级信息)支持继承的机制,一般被包含在主 .dts 文件(描述完整板级信息)中。这种方法减少了冗余并提升了模块化(共有的部分只需要在被包含文件中定义一次即可)。
八、验证 Linux 中的 Device Tree
语法检查是通过 Device Tree 编译器(dtc)处理的,但是 dtc 只确保正确的语法,而不是语义。语义验证是通过 YAML bindings 完成的:
- 语法验证:dtc 确认 Device Tree 是否符合语法规则
- 语义验证:
make dt_bindings_check 验证 YAML bindings 本身是否规范
make dtbs_check 根据YAML bindings 验证Device Tree 是否符合规范
九、在 runtime 调整 Device Tree
在 Linux 系统中, Device Tree Blob(dtb)可以在 boot 期间调整。U-boot,流行的bootloader,可以在把 DTB 传给 Linux 之前对它进行批处理,调整参数,如 RAM 基地址、kernel指令行、MAC地址。这种动态编辑通过 fdt 指令完成。
十、Device Tree 的设计原则
在使用Device Trees时,有几条设计指导原则:
- 描述硬件,而非结构:Device Tree应该只用来描述硬件属性和集成,而不是OS会如何组织和使用这些硬件
- OS-无关:理想情况下,Device Tree 在不同的操作系统(Linux,FreeBSD,U-Boot)之间是保持不变的。
- 硬件集成,而非内部实现:Device Tree描述部件是如何连接的,而不是它们的内部实现机制。具体细节有设备驱动代码管理。
和任何设计一样,这些原则有时是可以被打破的。
十一、Device Tree 和 Linux 驱动:平台驱动匹配
在 Linux 中,驱动器按照Device Tree所描述的和硬件交互。平台驱动器,比如/drivers/tty/serial/imx.c下的那些,使用compatible 字符串和Device Tree中列出的设备匹配。
十二、Device Tree 的关键属性
一些 Device Tree 中常用的属性包括:
- reg:为内存映射设备定义基本地址和寄存器大小
- interrupts:指定设备使用的中断行和它所连接的中断控制器
- clocks:设备所使用的时钟
- dmas:DMA控制器和通道
- status:okey 意味着设备是可用的
- pinctrl-*:指定引脚复用
这些属性定义了硬件部件是如何集成到系统中的。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐

所有评论(0)