文章目录
什么是设备树,为什么引入设备树?
设备树(Device Tree,简称DT)是一种数据结构,用于描述硬件的布局和连接方式。它最初由Open Firmware引入,后来被Linux社区采用,用于解决在嵌入式系统中硬件描述的问题。设备树通过一种独立于硬件平台的方式,向操作系统内核提供设备信息,使得内核不再需要内置具体的硬件配置代码,从而提高了系统的可移植性和灵活性。
引入设备树的主要原因包括:
- 平台独立性:设备树使硬件描述从内核代码中分离出来,通过一份设备树文件(通常是.dts文件)来描述硬件。这样,同一内核可以运行在不同硬件平台上,只需提供相应的设备树文件。
- 简化内核代码:将硬件描述从内核代码中抽离出来,可以减少内核代码的复杂度和维护难度,特别是对于嵌入式系统和多平台支持的内核。
- 动态配置:设备树使得硬件配置可以在系统启动时动态加载和解析,而不需要重新编译内核。这样可以更方便地添加、删除和修改硬件配置。
- 硬件抽象:设备树提供了一种标准化的方式来描述硬件,使得硬件厂商和内核开发者可以更方便地沟通和协作。
设备树基本概念
相关术语解释
-
DT(Device Tree,设备树):设备树是一种数据结构,用于描述计算机系统的硬件布局。它包含系统中的各种硬件组件及其连接关系,通过一个层次化的树结构来表示。设备树用于向操作系统内核提供硬件信息,使内核能够正确地初始化和操作这些硬件。
-
FDT(Flattened Device Tree,扁平设备树):FDT是设备树的一种二进制表示形式,适用于在内核引导时使用。FDT由设备树编译器(dtc)生成,是dts(设备树源文件)编译后的产物。它以一种紧凑的方式存储设备树数据,使其更适合在系统启动时加载和解析。
-
dts(Device Tree Source,设备树源文件):dts文件是设备树的源文件,以文本格式编写,描述了系统中的硬件设备及其属性。dts文件通常由硬件开发人员或系统集成商编写,并在系统启动前编译成dtb文件供内核使用。
-
dtsi(Device Tree Source Include,设备树源包含文件):dtsi文件是设备树源文件的包含文件,类似于编程中的头文件。它们通常包含共享的硬件描述,用于不同的dts文件中,通过
#include
指令包含到具体的dts文件中。这样可以避免重复代码,并且便于管理和维护。 -
dtb(Device Tree Blob,设备树二进制文件):dtb文件是由dts文件编译生成的二进制文件,包含了设备树的扁平表示形式(FDT)。dtb文件在系统启动时由引导加载程序(如U-Boot)加载,并传递给操作系统内核,以便内核根据其中描述的信息初始化硬件。
-
dtc(Device Tree Compiler,设备树编译器):dtc是将dts文件编译为dtb文件的工具。dtc可以将设备树源文件(dts)编译成设备树二进制文件(dtb),也可以将dtb反编译为dts,以便进行调试和修改。
DTS,DTSI,DTB,DTC之间的关系
设备树源码所在地
在Linux内核源码中,设备树源码一般存放在,源码/arch/arm64/boot/dts 该目录下
如果是32位的话,设备树源码在 源码/arch/arm/boot/dts
使用DTC编译设备树
首先要找到DTC编译器,一般存放在内核目录下的 scripts/dtc文件夹
注:要先编译Linux内核源码之后,才能生成DTC编译器
写一个最简单的设备树源码
/dts-v1/;
/ {
compatible = "simple-system";
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
device_type = "cpu";
reg = <0>;
compatible = "simple-cpu";
};
};
};
基本的DTC编译命令
dtc -I dts -O dtb -o output_file.dtb input_file.dts
dtc
: 调用设备树编译器。
-I dts
: 指定输入文件的格式为设备树源文件(DTS)。
-O dtb
: 指定输出文件的格式为设备树二进制文件(DTB)。
-o output_file.dtb
: 指定输出文件的名称。
input_file.dts
: 指定输入的设备树源文件。
基本的反编译命令
dtc -I dtb -O dts -o example.dts example.dtb
效果演示(编译与反编译)
设备树语法
设备树(Device Tree)基本语法如下:
1. 节点 (Node)
设备树的核心是节点,每个节点表示一个硬件设备或逻辑设备。每个节点有一个名称,并且可以包含属性和子节点。同级路径下节点名称不能相同,不同级路径的节点名称可以重复。对节点名称一般要体现设备的类型
节点名称格式:[标签]:<名称>[@<设备地址>] ,其中标签和设备地址是可选的,名称必须要有
/node_name {
property_name = value;
subnode_name {
property_name = value;
};
};
2. 属性 (Property)
属性是节点中的键值对,用于描述设备的特性。属性可以是字符串、整数、布尔值或字节数组。
典型属性:reg 属性
reg 属性可以用来描述地址信息。比如说寄存器的值
格式如下:
reg = <address1 len1 address2 len2 …>
举例:
reg = <0x2200000 0x4000>
reg = <0x2050000 0x4000
0x2150000 0x4000
0x2170000 0x4000
>
#address-cell 和 #size-cell 用来描述子节点中reg信息中的地址和长度信息
举例:
node_name {
#address-cell = <1>;
#size-cell = <1>;
node_chird {
reg = <0x02000000 0x4000> /* 一个地址 一个长度 */
}
};
node_name {
#address-cell = <2>;
#size-cell = <0>;
node_chird {
reg = <0x02 0x40> /* 两个地址 没有长度 */
}
};
model 属性 一般用来表述一些信息,比如说设备的名称和版本等等
status 属性 ,与设备状态有关系
属性值 | 描述 |
---|---|
okay | 设备为可用状态 |
disable | 设备为不可用状态 |
fall | 设备为不可用状态,并检测到了错误 |
fall xxx | 设备为不可用状态,并检测到了错误,错误内容为xxx |
compatible 属性 :非常重要的属性,用来和驱动进行匹配的,匹配成功之后,会调用驱动中的probe函数。
compatible = "mixel,lvds-phy";
匹配的时候优先和第一个值mixel进行匹配,如果没有就使用第二个值进行匹配。
3. 包含文件 (Include Files)
dtsi文件是设备树的包含文件,可以用于共享和重用硬件描述。
#include "common.dtsi"
node_name {
property_name = value;
};
4. 节点路径 (Node Path)
节点通过路径进行引用,路径用斜杠分隔。
/ {
node1 {
node2 {
property = <0>;
};
};
};
5. 别名 (Alias)
别名用于为节点提供一个简短的名称,方便引用。一个特殊的节点,定义别名的目的就是为了方便引用节点,可以批量地定义节点,可以使代码更加整齐
/ {
aliases {
alias_name = &node_name;
};
node_name: node_label {
property_name = value;
};
};
6. 复合节点 (Phandle)
节点可以通过引用其他节点的方式进行关联,使用&
符号引用节点标签。
/ {
node1: node1_label {
property_name = <&node2_label>;
};
node2: node2_label {
property_name = value;
};
};
7. 定义与引用 (Definition and Reference)
节点和属性的值可以定义为常量,并在其他地方引用。
#define MY_CONSTANT 0x12345678
node_name {
property_name = <MY_CONSTANT>;
};
示例设备树
以下是一个完整的示例设备树:
/dts-v1/;
/ {
compatible = "my,board";
model = "My Custom Board";
aliases {
serial0 = &uart0;
};
cpu0: cpu@0 {
device_type = "cpu";
compatible = "arm,cortex-a9";
reg = <0>;
};
memory {
device_type = "memory";
reg = <0x80000000 0x20000000>; /* 512MB at 0x80000000 */
};
uart0: serial@101f1000 {
compatible = "ns16550a";
reg = <0x101f1000 0x1000>;
interrupt-parent = <&intc>;
interrupts = <1 4>;
};
intc: interrupt-controller@10140000 {
compatible = "arm,gic";
reg = <0x10140000 0x1000>;
interrupt-controller;
#interrupt-cells = <3>;
};
};
关键点总结
- 节点用大括号
{}
包围。 - 属性用键值对表示,键是属性名,值是属性值。
- 使用
#include
引入外部 dtsi 文件。 - 使用别名和 phandle 进行节点间的引用。
- 使用定常量定义和引用来简化配置。
设备树通过这些语法元素,提供了一种灵活、可扩展的方式来描述硬件结构和配置,使得硬件描述与操作系统内核分离,提高了系统的可移植性和维护性。