一.设备树的概念
设备树:是一种描述硬件资源的数据结构,不是将设备的每个细节都硬编码到操作系统中,而是可以在引导时传递给操作系统的数据结构中描述硬件的许多方面。
设备树是描述一个硬件平台的硬件资源。这个“设备树”可以被bootloader(uboot)传递到内核, 内核可以从设备树中获取硬件信息。在操作系统(OS)引导阶段进行设备初始化(DTB文件在linux内核启动的时候内核解析),解析之后设备树就被放到内存在上(逻辑结构:树状结构)。如果某个驱动需要使用设备信息,直接从设备树上获取对应的设备信息即可。
树的主干就是系统的总线,在设备树里称为“根节点”。比如I2C控制器,SPI控制器,CAN控制器等都是接到系统主线上的分支,在设备树上称为“根节点的子节点”
设备树可以像头文件(.h)那样,一个设备文件引用另一个设备文件,实现“代码”的重用(复用),例如GEC6818是一款基于ARM公版开发板的产品,它采用了S5P6818芯片作为处理器,如果多个硬件平台都是用S5P6818芯片作为主控芯片,那么我们可以把S5P6818芯片的硬件资源写到一个单独的设备树文件里面一般使用“.dtsi”后缀,其他设备树文件直接使用“#includexxxx”引用即可。
DTS、DTC和DTB它们是常见的几个缩写:
DTS 是指.dts格式的文件,是一种ASII 文本格式的设备树描述,也是我们要编写的设备树源码,一般一个.dts文件对应一个硬件平台,位于Linux源码的“/arch/arm/boot/dts”目录下。
DTC 是指编译设备树源码的工具,一般情况下我们需要手动安装这个编译工具。
DTB 是设备树源码编译生成的文件,类似于我们C语言中“.C”文件编译生成“.bin”文件。
dtb通过Bootloader引导程序加载到内核。
二.编译设备树
首先我们需要编译好内核(通常只需一次编译好内核,编译内核的时候会生成的dtc工具),内核编译的位置在 kernel
目录中 ,内核中的dtc工具位置在 内核源码/scripts/dtc/dtc
。
使用方法:
/usr/src/linux-source-4.4.0/scripts/dtc/dtc -I dts -O dtb -o xxx.dtb xxx.dts
也可以反编译:
/usr/src/linux-source-4.4.0/scripts/dtc/dtc -I dtb -O dts -o xxx.dts xxx.dtb
红色为dtc工具的绝对路径,要加上。
三.设备树语法
头文件:
头文件:设备树是可以像C语言那样使用“#include”引用“.h”后缀的头文件,也可以引用设备树“.dtsi”后缀的头文件。imx6ull.dtsi由NXP官方提供,是一个imx6ull平台“共用”的设备树文件。
#include "skeleton.dtsi"
节点:
设备树节点:“/ {…};”表示“根节点”,每一个设备树只有一个根节点。不同文件的根节点最终会合并为一个。在根节点内部的“chosen{…}”、memory{…}”、“reserved-memory{…}”、“leds{…}”等字符,都是根节点的子节点。
命名:对节点命名的时候要体现设备的类型
格式:[标签]:<名称>[@<设备地址>] (这里的设备地址没有实际意义,只是让节点名称更人性化,方便阅读,一般设置为外设的物理地址(按照惯例,如果一个节点有 reg 属性,那么该节点的名字就必须包含设备地址,这个设备地址就是 reg属性里第一个地址值。)。另外,当同级设备节点名称相同时,可以通过设备地址进行区分且编译不报错!。)同级节点名称不能相同,不同级的可以相同。
标签,也叫别名,方便引用。比如通过&CPU1就可以访问“cpu@1”这个节点
属性:
reg属性:
可编址设备使用以下属性将地址信息编码进设备树:
reg
#address-cells
#size-cells
每个可编址设备都有一个reg,它是一个元组表,形式为:
reg =<地址1 长度1[地址 2长度 2][地址3 长度3]...>。
每个元组都表示该设备使用的一个地址范围。每个地址值是一个或多个 32 位整型数列表,称为 cell。同样,长度值也可以是一个 cell 列表或者为空。由于地址和长度字段都是可变大小的变量,那么父节点的 #address-cells 和#size-cells 属性就用来声明各个字段的 cell 的数量。换话说,正确解释一个 reg 属性需要用到父节点的#address-cells 和#size-cells 的值。
model属性:
它的值是一个字符串,用于描述一些信息,比如设备的名字等。
model="This is my device"
status属性,该属性和设备状态有关,值是字符串,有几个状态可选:
okay: 设备是可用状态
disable: 设备是不可用状态
fail: 设备是不可用状态并且检测到了错误
fail-sss: 设备是不可用状态并且检测到了错误,sss是错误内容
compatible 属性:
这是一个非常重要的属性,他是用来和驱动进行匹配的。匹配成功以后,会执行驱动中的probe函数。
举例:
compatible = "arm,p1330","arm,primecell";
匹配的时候会先使用第一个值进行匹配,没有就使用第二个值进行匹配。
range属性:
该属性提供了子节点地址空间和父地址空间的映射(转换)方法,常见格式是 <子地址、父地址、地址长度>。如果父地址空间和子地址空间相同则无需转换。
比如对于#address-cells和#size-cells都为1的话,以ranges=<0x0 0x10 0x20>为例,表示将子地址的从0x0~(0x0 + 0x20)的地址空间映射到父地址的0x10~(0x10 + 0x20)。
device_type属性:
device_type属性也是一个很少用的属性,只用在CPU和内存的节点上,值是字符串,用于描述这些节点。
chosen节点:(必须写在根节点下面)
chosen 节点并不代表一个真正的设备,只是一个为固件和操作系统传递数据的地方,如引导参数。chosen 节点里的数据也不代表硬件。如在 arch/arm/boot/dts/exynos4412-origen.dts 文件中的 chosen 节点定义如下:
chosen {
bootargs = "console=ttySAC2,115200";
};
设备树特殊节点:
aliases 节点用于指定节点的别名。因为引用一个节点要使用全路径,当子节点离根节点较远时,节点名就会显得比较冗长,定义一个别名则比较方便。下面把 spi 0这个节点定义了一个别名“spi0”。
aliases {
spi0 = &spi0;
...