# 设备树
设备树(Device Tree)是一种硬件描述机制,用于在嵌入式和操作系统中描述硬件设备的特性、连接关系和配置信息,它提供了一种与平台无关的方式来描述硬件,使得内核与硬件之间的耦合度降低,提高了系统的可移植性和可维护性。
## 文件说明及编译方式
DTS(Device Tree Source):DTS是设备树的源文件,采用一种类似文本的语法来描述硬件设备的结构、属性和连接关系。DTS文件以.dts为扩展名,通常由开发人员编写,它是人类可读的形式,用于描述设备树的层次结构和属性信息。
DTSI(Device Tree Source Include):DTSI文件是设备树源文件的包含文件。它扩展了DTS文件的功能,用于定义可重用的设备树片段。DTSI文件以.dtsi为扩展名,可以在多个DTS文件中包含和共享,通过使用DTSI,可以提高设备树的可重用性和可维护性(和C语言中头文件的作用相同)。
DTB(Device Tree Blob):DTB是设备树的二进制表示形式。DTB文件是通过将DTS或DTSI文件编译而成的二进制文件,以.dtb为扩展名,DTB文件包含了设备树的结构、属性、和连接信息,被操作系统加载和解析。在运行时,操作系统使用DTB文件来动态识别和管理硬件设备。
DTC(Device Tree Compiler):DTC是设备树的编译器。它是一个命令行工具,用于将DTS和DTSI文件编译成DTB文件。DTC将文本格式的设备树源码转换为二进制的设备树表示形式,以便操作系统能够加载和解析。DTC是设备树开发中一个重要的工具。
编译命令格式:dtc -I dts -O dtb -o output.dtb input.dts
![image-20240419092034546](C:\Users\15755\AppData\Roaming\Typora\typora-user-images\image-20240419092034546.png)
反编译命令格式:dtc -I dtb -O dts -o output.dts input.dtb
![image-20240419092322956](C:\Users\15755\AppData\Roaming\Typora\typora-user-images\image-20240419092322956.png)
```c
/dts-v1/; //设备树版本信息,可写可不写
/{
//根节点开始
/*
次处添加注释,描述根节点的属性和配置
*/
};
节点格式
子节点:设备树中的子节点是根节点的直接子项,用于描述具体的硬件设备或设备集合。字节点采用以下特定的格式来表示:
[label:] none-name@[unint-address] {
[properties definitions]
[child nodes]
};
节点标签(label):可选;节点标签是一个可选的标识符,用于在设备中引用该节点。标签允许其他节点直接引用此节点,以便在设备树中建立引用关系。
节点名称(none-name):节点名称是一个字符串,用于标识该节点在设备树中的位置。节点名称通常是硬件设备的名称,但必须在设备树中是唯一的。
单元地址(unint-address):(可选);单元地址用于标识设备的实例。可以是一个整数、一个十六进制值或一个字符串。单元地址的目的就是区分相同类型设备的不通实例。
属性定义(properties definitions):属性定义是一组键值对,用于描述设备的配置和特性。属性可根据设备的需求进行定义,例如寄存器地址、中断号、时钟频率等。
字节点(child nodes):子节点是当前节点的子项,用于进一步描述硬件设备的子组件或配置。子节点可以包含自己的属性定义和更深层次的子节点,形成设备树的层次结构。
节点属性(reg、address-cells、size-cells、model、status、compatible)
reg属性
reg属性:用于在设备树中指定设备的寄存器地址和大小,提供了与设备树中的物理设备之间的寄存器的映射关系。
reg属性可以在设备节点中由单个值格式和列表值格式两种格式。
单个值格式:适用于描述单个寄存器的情况。adderess是设备的其实寄存器地址,可以是一个整数或十六进制值;size表示寄存器的大小,即占用的字节数
reg = <address size>;
例如:假设有一个设备节点my_device,使用单个值格式的reg属性来描述一个4字节寄存器的地址和大小,可以这样定义:
my_device{
compatible = "vendor ,device";
reg = <0x1000 0x4>;
//其他属性和子节点的定义
};
列表值格式:当设备具有多个寄存器区域时,可以使用列表值格式的reg属性来描述每个寄存器区域的地址和大小,通过这种方式,可以指定多个寄存器的位置和大小,以描述设备的完整寄存器映射。
reg = <address1 size1 address2 size2 ...>
例如:一个设备节点my_device,具有两个寄存器区域,分别是8字节和4字节大小的寄存器。
my_device{
compatible = "vendor,device";
reg = <0x1000 0x8 0x2000 0x4>
};
address-cells和size-cells属性
#address-cells和#size-cells属性用于指定在上个小节中要设置的设备树中地址单元和大小单元的位数
实例
node1{
#address-cells = <1>;
#size-cells = <1>;
node1-child {
reg = <0x02200000 0x4000>;
//其他属性和子节点的定义
};
};
由于#address-cells的值为1,表示使用一个单元来表示地址;#size-cells的值为1,表示使用一个单元来表示大小。
解释后的地址和大小值如下:
地址部分: 0x02200000表示一个地址单元,地址为0x02200000
大小部分:0x4000表示一个大小单元,大小为0x4000;
实例
node1{
#address-cells = <2>;
#size-cells = <0>;
node1-child {
reg = <0x0000 0x0001>;
//其他属性和子节点的定义
};
};
地址部分:第一个地址为0x0000,第二个地址为 0x0001
这种使用#address-cells和#size-cells属性的方式使得设备树可以适应不同设备的寄存器映射和大小表示方式。
model属性
model属性用于描述设备的型号或者名称。model属性可选。model的值是一个字符串
my_device{
compatible = "vendor,device";
model = "My Device LYT" ;
//其他属性和子节点的定义
};
model属性通常用于标识和区分不同的设备,特是当设备节点的compatible属性相同或相似是,通过使用不同的model属性值,可以更加准确的确定所使用的设备类型,类似name。
status属性
status属性用于描述设备或节点的状态。用于表示设备或节点的可用性或操作状态。
status属性的值可以是以下几种:
okay:表示设备或节点正常工作,可用。
disabled:表示设备或节点被禁用,不可用。
reserved:表示设备或节点已被保留,暂时不可用。
fail:表示设备或节点初始化或操作失败,不可用。
compatible属性
compatible属性用于描述设备的兼容性信息。用于识别设备节点与驱动程序之间的匹配关系。
compatible属性的值是一个字符串或字符串列表,用于指定设备节点与相应的驱动程序或设备描述符兼容的规则,通常,compatible属性的值由设备的厂商定义,并且在设备树中使用。
以下是常用的compatible属性值的示例:
①单个字符串值:“vendor,device”,用于指定设备节点与特定厂商的特定设备兼容。
②字符串列表:[“vendor,device1”,“vendor,device2”],用于指定设备节点与多个设备兼容,通常用于设备界定啊具有多种变体或配置
③通配符匹配:“vendor,*”,用于指定设备节点与特定厂商的所有设备兼容,不考虑具体的设备标识。
示例
my_device{
compatible = ["vendor,device1","vendor,device2"];
status = "okay
};
表示设备节点与厂商的device1和device2兼容,设备处于正常工作状态。
通过使用compatible属性,设备树可以提供设备和驱动程序之间的匹配信息。当设备树被操作系统或设备管理软件解析时,会根据设备节点的compatible属性值来选择合适的驱动程序进行设备的初始化和配置。
特殊节点(aliases、chosen、device_type、自定义属性)
aliases节点
aliases节点是一个特殊的节点,用于定于设备别名。该节点位于设备树的根部,并具有节点路径 /aliases.
aliases节点是一个容器节点,包含一组属性,每个属性都代表一个设备别名。每个属性的名称是别名的标识符,而属性的值是被引用设备节点的路径或设备树中其他节点的路径。
示例
aliases{
mmc0 = &sdmmc0;
mmc1 = &sdmmc1;
mmc2 = &sdhci;
serial0 = "/simple@fe000000/serial@11c500";
};
在上述例子中,由四个别名的定义:
mmc0别名与设备树中的sdmmc0节点相关联,通过使用别名mmc0,其他设备节点设备或客户端程序可以更方便地引用sdmmc节点,而不必直接使用其完整路径。
其余类似;
注:aliases节点中定义的别名只在设备树内部可见,不能在设备树之外引用,他们主要用于设备树内部组织和引用。
chosen节点
chosen节点是设备树中的一个特殊节点,用于传递和存储系统引导和配置的相关信息。位于设备树的根部,并具有路径 /chosen
chosen节点通常包含以下子节点和属性:
①bootargs:用于指定存储引导内核时传递的命令行参数。它可以包含诸如内核参数、设备树参数等信息。在引导过程中,操作系统或引导加载程序可以读取该属性来获取启动参数。
②stdout-path:用于指定用于标准输出的设备路径。在引导过程中,操作系统可以使用该属性来确定将控制台输出发送到哪个设备,例如串口或显示屏。
③firmware-name:用于指定 系统固件的名称。它可以用于表示所使用的引导加载程序或固件的类型和版本。
④linux , initrd-statrt 和linux , initrd-end:这些属性用于指定linux内核初始化ARM磁盘(initrd)的起始地址和结束地址。这些信息在引导过程中被引导加载程序使用,以将initrd加载到内存中供内核使用。
chosen节点提供了一种通用的机制,使得不同的设备树和引导系统可以在传递信息方面保持移植行,并且可以根据具体需求扩展和自定义。
device_type节点
device_type用于描述设备类型的节点,通常作为设备节点的属性存在。设备类型包括但不限于:
- cpu:中央处理器
- memory:内存设备
- display:显示设备
- serial:串行通信设备
- ethernet:以太网设备
- usb:通用串行总线设备
- i2c:使用I2C总线通信的设备
- gpio:表示通用输入/输出设备
- pwm:脉宽调制设备
设备树–中断
中断相关属性:interrupts、interrupt-controller、#interrupt-cells、interrupt-parent四种常见属性。
interrupts属性用于指定设备的中断相关信息,描述了中断控制器的类型、中断号以及中断触发类型。
interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>
第一个参数中断控制寄存器类型:常见的类型包括GIC、IRQ、等。示例中表示表示中断控制器的类型为GIC SPI中断。
中断控制器负责管理系统中的中断信号,它可以是硬件中的专用中断控制器,也可以是处理器内部的中断控制器。
第二个参数指定了设备所使用的中断号。
第三个参数指定了中断的触发类型,即中断信号的触发条件。
#define IRQ_TYPE_NONE 0 //无中断触发类型
#define IRQ_TYPE_EDGD_RISING 1 //上升沿触发
#define IRQ_TYPE_EDGD_FALLING 2 //下降沿触发
#define IRQ_TYPE_EDGE_BOTH (1|2) //双边沿触发
#define IRQ_TYPE_LEVEL_HIGH 4 //高电平触发
#define IRQ_TYPE_LEVEL_LOW 8 //低电平触发
interrupt-controller
该属性是设备树中用于描述中断控制器的属性之一,提供了中断控制器的相关信息,以便操作系统和其他设备额能够正确配置和使用中断系统
interrupt-controller属性用于标签当前节点所描述的设备是一个中断控制器,中断控制器是硬件或软件模块,负责管理和分发中断信号。它接受来自各种设备的中断请求,并根据优先级和配置规则分发中断给相应的处理器或设备。
interrupt-controller属性本身没有特定的属性值,只需出现在节点的属性列表中即可。出现该属性的存在即表示该节点描述的设备是中断控制器。
interrupt-parent
该属性是设备树中用于建立中断信号源与中断控制器之间关联的属性。指定了中断信号源所属的中断控制器。
device{
interrupt-parent = <&gpio>;
};
#interrupt-cells
该属性用于描述中断控制器中每个中断信号源的中断编号单元的数量。中断编号单元是指用于表示中断号和其他相关信息的固定大小的单元,通过指定中断编号单元的数量,操作系统可以正确解析和处理中断信息,并将其与中断控制器和中断信号源进行关联。
interrupt-cells属性值是一个整数,表示中断编号单元的数量若为3即interrupts中的3个参数,若为2则只有其中2个参数
/dts-v1/;//设置树文件的头部,指定了使用的设备树语法版本
#include "dt-bindings/pinctrl/rockchip.h" //定义引脚控制器相关的绑定
#include "dt-bindings/interrupt-controller/irq.h" //定义中断控制器相关的绑定
/{ //表示设备树根节点的开始
model = "This is my devicetree!"; //指定设备树的模拟名称,描述为“This is my devicetree!”
ft5x06@38{
//指定了设备节点的兼容性字符串,表示该设备与“edt,edt-ft5206”兼容
compatible = "edt,edt-ft5206";
//指定中断的父节点,即中断控制器所在的节点
interrupt-parent = <&gpio3>;
//指定了中断信号的配置: 中断信号的引脚 中断触发类型
interrupts = <RK_PA5 IRQ_TYPE_EDGE_RISING>;
};
};
设备树–时钟
时钟用于描述硬件设备和系统中的时钟源以及时钟相关的配置和连接关系。其功能用于同步和定时各种硬件设备的操作。时钟分为两个部分:时钟生产者和时钟消费者。
时钟生产者
时钟生产者是负责生成和提供时钟信号的硬件或软件模块,可以是时钟控制器、PLL、时钟发生器
设备树节点:时钟生产者在设备树中以时钟节点的形式表示
时钟节点属性 (clock-cells、clock-frequency、assigned-clocks、addigned-clock-rates、clock-indices、addigned-clock-parents)
clock-cells:该属性用于指定时钟编号的位数,它是一个整数值,表示时钟编号的位数,通常情况下,当clock-cell为0时表示一个时钟,为1表示多个时钟。示例如下:
//示例一:单个时钟
osc24m: osc24m{
compatible = "clock";
clock-frequency = <24000000>;
clock-output-names = "osc24m";
#clock-cell = <0>;
};
//示例2:多个时钟
clock: clock {
#clock-cells = <1>;
clock-output-names = "clock1","clock2";
};
clock-frequency:是设备树中用于指定时钟频率的属性
assigned-clocks:用于标识时钟消费者节点所使用的时钟源。它是一个整数组,每个元素对应一个时钟编号,时钟编号·是指时钟生产者节点(如时钟控制器)所提供的时钟源的编号。通过在时钟消费节点中使用assigned-clocks属性,可以指定该节点所需的时钟源。
assigned-clock-rates:用于指定每个时钟源的时钟频率。是一个整数数组,每个元素对应一个时钟源的频率,以Hz为单位表示。assigned_clock-rates属性的元素数量和顺序应与assigned-clocks属性中的时钟编号相对应。
cru:clock-controller@fdd20000{
#clock-cells=<1>;
assigned-clocks=<&pmucru CLK_RTC_32K>,<&cru ACLK_RKVDEC_PRE>;
assigned-clock-rates=<32768>,<300000000>;
};
clock-indices:用于指定时钟消费者节点所使用的时钟源的索引值,是一个整数数组,每个元素对应一个时钟源的索引。
时钟索引是指时钟生产者节点(如时钟控制器)所提供的时钟源的编号。通过在时钟消费者节点中使用clock-indices属性,可以明确指定该节点所需的时钟源,并按照特定的顺序进行匹配。
scpi_dvfs:clocks-0{
#clock-cells =<1>;
clock-indices = <0>,<1>,<2>;
clock-output-names = "atlclk", "aplclk", "gpuclk";
};
scpi_clk:clocks-1{
#clock-cells=<1>;
clock-indices=<3>;
clock-output-names="pxlclk";
};
在第一个节点中“atlclk”,“aplclk”,"gpuclk"三个时钟源的索引就分别被设置了0,1,2,在第二个节点中“pxlclk”时钟源的索引值被设置为了3.
assigned-clock-parents:用于指定时钟消费者节点所使用的时钟源的父时钟源。它是一个时钟源引用的数组,每个元素对应一个父时钟源的引用。
clock:clock{
assigned-clocks=<&clkon 0>,<&pll 2>;
assigned-clocks-parents=<&pll 2>;
assigned-clock-rates= <115200>,<9600>;
};
上述设备树表示了一个名为clock的时钟消费者节点,具有以下属性:
assifned-clocks 属性指定了该节点使用的时钟源,引用了两个时钟源节点:clkcon0和pll2
assifned-clock-parents 属性指定了这些时钟源的父时钟源,引用了pll2时钟源节点
assigned-clock-reates 指定了每个时钟源的时钟频率,分别是115200和9600。
时钟消费者
时钟消费者是依赖时钟信号的硬件设备或模块。他们通过引用时钟生产者节点提供的时钟源来获取时钟信号。
设备树节点:时钟消费者在设备树中的节点中使用属性来引用时钟生产者的时钟源
时钟消费者属性:
clocks:用于指定时钟消费者节点所需的时钟源,是一个整数数组,每个元素是一个时钟编号,表示时钟消费者需要的一个时钟源。
clock-names:可选属性,用于指定时钟消费者节点所需时钟源的名称。是一个字符串数组,与clocks数组一一对应,用于提供时钟源的描述性名称。
clock:clock{
clocks=<&cru CLK_VOP>;
clock-names="clk_vop";
};
clocks指定了该节点使用的时钟源,引用了cru节点中的CLK_VOP时钟源。
clock-names:指定了时钟源的名称