本文目录
设备树(Device Tree,简称 DT)是描述硬件配置信息的一种数据结构,常用于嵌入式系统,尤其是在 ARM 架构的系统中。设备树描述了系统的硬件布局,使得操作系统可以在不依赖具体硬件信息的情况下进行硬件初始化和驱动加载。
一、相关知识点
1. 为什么要引入设备树?
在讲平台总线模型的时候。平台总线模型是把驱动分成了俩个部分,一部分是device
,一部分是driver
,设备信息和驱动分离这个设计非常的好。device部分是描述硬件的。但是随着Linux文持的硬件越来越多,在内核源码下关于硬件描述的代码也越来越多。并且每修改一下就要编译一次内核。
长此以往Linux内核里面就存在了大量”垃圾代码”,而且非常多,这里说的“垃圾代码”是关于对硬件描述的代码。从长远看,这些代码对Linux内核本身并没有帮助,所以相当于Linux内核是“垃圾代码”。但是并不是说平台总线这种方法不好。
为了解决这个问题,设备树就被引入到了Linux上。使用设备树来代替之前编译进内核的device
文件,并从内核中分离了出来,成为了一个单独的部分。对硬件修改以后不必重新编译内核。直接需要将设备树文件编译成二进制文件,在通过bootloader传递给内核即可。虽然用设备树替换了原来的device部分,但是平台总线模型的匹配和使用基本不变。所以设备树就是用来描述硬件资源的文件。
2. 基本概念
dts(Device Tree Source): 设备树源码,使用一种结构化的语言来描述硬件。文件扩展名为 .dts
。
dtsi(Device Tree Source include): 用于描述一些通用的设备树文件。
dtc(Device Tree Compiler): 设备树编译器,将 .dts
文件编译成二进制设备树文件(.dtb
)。
dtb(Device Tree Blob): 设备树二进制,编译后的二进制文件,内核在启动时加载并解析该文件。
解释:dtsi
文件的作用
假设我们有两个开发板,一个开发板上有led、beep等硬件设备,另一个开发板上有led、screen等硬件设备,那么我们就可以在dtsi
文件中写两个开发板共有的硬件设备的设备树,即含有led的设备树。这样我们在单独编写某个开发板的设备树时,只需要包含这个dtsi
文件,并描述自己开发板独有的硬件信息即可。
二、设备树的结构及基本语法
1. 最简设备树的结构
设备树是一棵树形结构,下述第三行的/
为根节点表示整个系统,即设备树的树根。子节点在根节点下定义和描述,每个子节点表示一个设备或设备的一部分。每个子节点有属性,属性包含该设备的具体配置信息。子节点下也可以有子子节点,以此类推。
my_tree.dts
/des-v1/; //设备树的版本,这个是必须要写的!不写的话编译会报错。
/{ //根节点
[子节点1]
[子节点2]
...
};
2. 子节点名称
子节点名称中[ ]
为可选项。[标签]
为子节点名称的别名,可以通过引用标签来引用该节点。[@<设备地址>]
主要用于区分设备,让节点名称更人性化,方便阅读,并无实际意义。
注意:同级节点名称不能相同,不同级的节点名称可以相同。
[标签]: <名称> [@<设备地址>]
3. 子节点格式
[label]: node [@unit-address ]{
[属性]
[子子节点]
};
例如:
led:goio@0{
[属性]
node-child{
}
}
4. 常用节点属性
在设备树中,节点属性用于描述硬件设备的具体信息和配置。
(1)model属性
model属性的值是一个字符串,一般用model描述一些信息。比如设备的名称、名字等。例如:model=“this is my DT”;
。该属性通常出现在设备树的根节点中,提供一个简洁的描述,帮助识别设备的具体型号和版本,并无实际意义。
/des-v1/; //设备树的版本,这个是必须要写的!不写的话编译会报错。
/{ //根节点
model=“this is my DT”;
[子节点]
...
};
(2)reg属性
指定设备在内存中的地址和大小。比如寄存器地址。
reg = <起始地址,地址长度>;
例如:reg=<0x202002, 0x40>
,描述了一端起始地址为0x202002
,地址长度为0x40
的地址信息。
●重要: reg属性为可变参,具体参数长度由另外两个属性#address-cell
和#size-cells
决定。
(3)#address-cell、#size-cells属性
该属性用于描述子节点中地址和大小信息的格式。#address-cell
用来描述reg属性中用几个数来表示起始地址,#size-cells
用来描述reg属性中用几个数来表示地址的大小。注意:描述的是子节点中的地址格式!!
举例:
#address-cell= <1>; //reg属性中用1个数表示地址
#size-cells= <0>; //0个数表示地址大小
reg=<0x2202>; //则0x2202为地址。
#address-cell= <2>; //reg属性中用2个数表示地址
#size-cells= <2>; //2个数表示地址大小
reg=<0x00 0x2202 0x00 0x40>; //则0x00 0x2202描述地址,0x00 0x40描述地址大小。
(4)status属性
status属性是和设备的状态有关系的,status的属性值是字符串。属性值有下面几个状态可选。
属性值 | 描述 |
---|---|
okay | 设备是可用设备 |
disabled | 设备是不可用状态 |
fail | 设备是不可用状态且检测到了错误 |
(5)compatible属性
compatible属性是非常重要的一个属性。compatible是用来和驱动进行匹配的。匹配成功以后会执行驱动中的probe函数。该属性用于指定设备的类型和兼容性信息。操作系统利用这个属性来识别和初始化设备。例如compatible = "arm,cortex-a9";
举例:compatible="qjl-beep","qjl-led";
,在匹配的时候会先使用第一个值qjl-beep进行匹配,如果没有就会使用第二个值qjl-led进行匹配。
三、DTC编译设备树文件
编译设备树:dtc -I dts -O dtb -o xxx.dtb xxx.dts
反编译设备树:dtc -I dtb -O dts -o xxx.dts xxx.dtb
●具体步骤:
使用命令查找源码路径下的dtc编译器,如:
sudo find /opt/Ascend310B-source-opi -name "dtc"
。如果没有找到,则编译内核源码,会生成dtc
可执行文件。
编写设备树文件,使用命令进行编译。注意:要使用dtc的绝对路径,或者将dtc路径设置为环境变量加入
/etc/profile
文件中。