设备树学习
设备树官网为https://www.devicetree.org,里面有设备树说明文档(详细的使用请查阅此文档)。关于设备树的前世,这里就不介绍了(网上相关的文档很多)。这里主要介绍设备树的语法、使用。设备树(devicetree)用来描述一个系统硬件(system hardware)的硬件架构信息。比如一个这个板上有几个串口,串口的起始地址为多少,中断号为多少等。在设备树学习过程中,会用到两种文件类型加一个编译器命令,分别是
.dts
文件类型。此文将就是我们要编写的设备树文件。包含.dtsi
文件类型。.dtb
文件类型。此类型就是.dts
编译完成后生成的文件类型。dtc
编译器命令。用来编译.dts
文件或者反编译.dtb
文件。
工具链的安装
上面提到了设备树编译命令dtc
。要使用此命令,首先要安装它的工具链。可以用dtc -v
命令测试一下,系统之前有没有安装此编译链。如果没有安装,可以使用如下的步骤安装。
- 使用命令
sudo apt-get install device-tree-compiler
安装。 - 使用
dtc -v
命令测试是否安装成功。如果成功,会显示设备树的版本号。
设备树结构
设备树由一个根节点/
加若干个子节点构成。每个节点可以包含自己的属性。属性由property_name = 值
的格式组成。如下面程序,根节点/
中包含四个属性model
、compatible
、#address-cells
、#size-cells
和一个子节点memory@0
。子节点中又包含device_type
和reg
属性。这就已经完成了一个完整的设备树文件(假设文件名为test.dts),可以通过命令dtc -I dts -O dtb -o test.dtb test.dts
来编译它,完事就生成test.dtb
文件了。
/{
model = "0123456789";
compatible = "abcdefgh","abcdefghi";
#address-cells = <1>;
#size-cells = <1>;
memory@0 {
device_type = "memory";
reg = <0x0 0x20000000>;
};
};
当然,上面只是一个类似helloword的例子。我们还需要了解更多的语法知识。
节点
的完整定义格式如下,其中[]
中的东西是可选项。节点名称的命名约定为node-mame@unit-address
,其中node-mame
有官方推荐的名称,具体可以查看官方文档2.2节。unit-address
通俗一点说就是节点的起始地址。注意,unit-address
必须和此节点中reg
属性的第一个地址一致,当此节点没有reg
属性时,他必须省略。
根节点没有node-mame
和unit-address
。它只有一个/
。
[label:] node-mame[@unit-address] {
[properties definitions]
[child nodes]
};
属性的定义格式如下。
[label:] property-name = value;
其中属性可以分为
- 标准属性。设备树标准定义的,如
compatible
。后面会介绍标准属性。 - 非标准属性。用户自定义的属性。应添加一个字符串前缀,如
linux,network-index
.其中linux
就是前缀。
属性值用于描述属性的信息,可以是下面的几种类型。
empty
值为空。用于传送true/false
的信息。u32
大端格式的32位整型。如property-name = <0x11223344>
。u64
大端格式的64位整型。如property-name = <0x11223344 0x55667788>
。prop-encoded-array
用于记录任意数量的address,length
对。如reg = <0x08000000 0x00000400>
.string
字符串型。如property-name = "hello word"
。string list
字符串型列表。如property-name = "hello","word"
。phandle
一个独一无二的u32
型的值。用于设备树节点的引用。
标准属性
compatible
(兼容性)属性。- 值类型:stringlist.
- 描述:它由一个或者多个字符串组成。这个属性就是u-boot、linux等程序用来匹配驱动程序的。是一个很重要的属性。
modle
(模型)属性。- 值类型:string.
- 描述:用于指定设备模型。一般出现在根节点的属性中。简单的说,就是指定板卡名称吧。
status
属性。- 值类型:string.
- 描述:用于指示当前节点的状态,其属性值有
- “okey”
- “disabled”.
- “fail”
- “fail-sss”.
#address-cells
属性。- 值类型:string.
- 描述:这个属性也很重要,用于声明子节点中
reg
属性中的地址所占个数(单位是u32)。配合#size-cells
和reg
属性使用。
#size-cells
属性。- 值类型:string.
- 描述:用于声明子节点中
reg
属性中的长度所占个数(单位是u32)。可以为0.
reg
属性。- 值类型:prop-encoded-array.
- 描述:这应该是设备树中最重要的一个属性了吧。就是用来描述设备地址分配情况的。需要和上面的
#address-cells
、#size-cells
一起使用。比如#address-cells = <2>
,#size-cells = <1>
,reg = <0x080000000 0x00000000 0x00000400>
。那么reg
的地址为0x080000000 0x00000000
,长度为0x00000400
.
有关中断产生节点的中断属性;
- interrupt-parent
- phandle.
- 描述:用来指定中断所属关系。
- interrupts
- 值类型:prop-encoded-array。
- 描述:用于描述节点中断的信息。他可以被
interrupts-extended
属性覆盖。例如interrupts = <0xA 8>
.(对于 0xA、8具体代表什么以及有几个这样的描述值,是由中断控制节点来描述的)。
有关中断控制器的中断属性;
- #interrupt-cells
- 值类型:u32.
- 这个属性就是描述
interrupts
属性中应该有几个值。
- interrupt-controller
- 值类型:empty.
- 用来指明老子就是中断控制器。
.dtb
文件结构解析
设备树终归是要让目标程序去解析,提取信息。所以.dtb
文件必须有它固定的格式。因为这个格式也不是特别的难,所以了解一下它,能更加清晰的认识设备树以及u-boot
、linux
中的设备、驱动模型的联系。当然,设备树的官方文档中对齐讲解的更加细致,想抠细节的话可以查看官方文档。
.dtb
文件格式由三部分组成。
- small header.
- memory reservation block.
- structure block.
- strings block
编译、反编译
在我们把设备树编写完成后,需要对它编译,生成程序可以识别的二进制代码,即xxx.dtb
文件(前面也已经讲了此文件的格式)。当然,在u-boot
、linux
中,这些编译工作都交给了Makefile。设备树工具链的安装完成后(安装步骤前面也讲了),我们就可以使用编译命令了。建议先使用dtc --help
查看一下命令的用法,每个选项都有详细的介绍。下面只列举常用到的选项。
- -I 指定输入文件的类型。如果输入文件是
.dts
文件,那么就用-I dts
。如果输入文件是.dtb
文件,就用-I dtb
。 - -O 指定输出文件的类型。如果输出文件是
.dts
文件,那么就用-O dts
。如果出文件是.dtb
文件,就用-O dtb
。注意,是大写的字母O
。 - -o 指定输出文件存放位置及名称。如
-o my.dtb
。注意,是小写的字母O
。
有了这三个选项,我们就可以进行编译和反编译了。如要进行编译test.dts
文件,那么命令就是dtc -I dts -O dtb -o test.dtb test.dts
。如果要反编译test.dtb
,命令就是dtc -I dtb -O dts -o test.dts test.dtb
。
注意在编译时要将文件中的#include xxxx
修改位/#include/ xxx
不然编译是过不去的(会提示文件的include有错误)。
other
/dts-v1/ 文件版本
dts文件的注释风格与c语言一致。
chosen节点
dtb文件的相关结构位置:./scripts/dtc/./libfdt/fdt.h。
u-boot中的有关解析设备树的代码位置:./drivers/core/root.c
关于技术交流
此处后的文字已经和题目内容无关,可以不看。
qq群:825695030
微信公众号:嵌入式的日常
如果上面的文章对你有用,欢迎打赏、点赞、评论。