设备树的学习
什么是设备树
设备树(Device Tree),将这个词分开就是“设备”和“树”,描述设备树的文件叫做 DTS(Device
Tree Source),这个 DTS 文件采用树形结构描述板级设备,也就是开发板上的设备信息,比如
CPU 数量、 内存基地址、 IIC 接口上接了哪些设备、 SPI 接口上接了哪些设备等等,如图所示
在图中,树的主干就是系统总线, IIC 控制器、 GPIO 控制器、 SPI 控制器等都是接到系统主线上的分支。IIC 控制器有分为 IIC1 和 IIC2 两种,其中 IIC1 上接了 FT5206 和 AT24C02这两个 IIC 设备, IIC2 上只接了 MPU6050 这个设备。 DTS 文件的主要功能就是按照上图所示的结构来描述板子上的设备信息,
提示:以下是本篇文章正文内容,下面案例可供参考
一、设备节点
设备树是采用树形结构来描述板子上的设备信息的文件,每个设备都是一个节点,叫做设备节点,每个节点都通过一些属性信息来描述节点信息,属性就是键—值对。以下是从imx6ull.dtsi 文件中缩减出来的设备树文件内容:
其中第 1 行,“/”是根节点,每个设备树文件只有一个根节点。
第 2、 6 和 17 行, aliases、 cpus 和 intc 是三个子节点
第 10 行, cpu0 也是一个节点,只是 cpu0 是 cpus 的子节点。 每个节点都有不同属性,不同的属性又有不同的内容,属性都是键值对,值可以为空或任意的字节流
二、DTS启动内核的过程
接下来我们简单看一下 Linux 内核是如何根据设备树根节点的 compatible 属性来匹配出对应的 machine_desc, Linux 内核调用 start_kernel 函数来启动内核, start_kernel 函数会调用setup_arch 函数来匹配 machine_desc,找到匹配的 machine_desc 的过程就是用设备树根节点的compatible 属性值和 Linux 内核中 machine_desc 下.dt_compat 的值比较,看看那个相等,如果相等的话就表示找到匹配的 machine_desc。第 715~720 行,此循环就是查找匹配的 machine_desc 过程,第 716 行的 of_flat_dt_match 函数会将根节点 compatible 属性的值和每个 machine_desc 结构体中. dt_compat 的值进行比较,直至找到匹配的那个 machine_desc。
Linux 内核通过根节点 compatible 属性找到对应的设备的函数调用过程如下图所示
machine_desc 结构体中有个.dt_compat 成员变量,此成员变量保存着本设备兼容属性,当设备树中的compatible 属性值和linux内核中的_dt_compat 表里面的值有相等时,那么就表示 Linux 内核支持此设备。
三.创建一个小型模板设备树
在实际产品开发中,我们是不需要完完全全的重写一个.dts 设备树文件,一般都是使用 SOC 厂商提供好的.dts 文件,我们只需要在上面根据自己的实际情况做相应的修
改即可。在编写设备树之前要先定义一个设备,我们就以 I.MX6ULL 这个 SOC 例,我们需要在设备树里面描述的内容如下:
//设备树基础框架
/ {
compatible = "fsl,imx6ull-alientek-evk", "fsl, imx6ull";
cpus {
#address-cells = <1>;
#size-cells = <0>;
//CPU0节点
cpu0: cpu@0 {
compatible = "arm, cortex-a7";
device_type = "cpu";
reg = <0>;
};
};
//soc节点
soc {
#address-cells = <1>;
#size-cells = <1>;
compatible = "simple-bus";
ranges; //ranges 属性为空,说明子空间和父空间地址范围相同
//ocram节点
ocram: sram@00900000 {
compatible = "fsl,lpm-sram";
reg = <0x00900000 0x20000>;
};
//aips1节点
aips1: aips-bus@02000000 {
compatible = "fsl,aips-bus", "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
reg = <0x02000000 0x100000>;
ranges;
//ecspi1节点
ecspi1: ecspi@02008000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl,imx6ul-ecspi", "fsl,imx51-ecspi";
reg = <0x02008000 0x4000>;
status = "disabled";
};
}
//aips2节点
aips2: aips-bus@02100000 {
compatible = "fsl,aips-bus", "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
reg = <0x02100000 0x100000>;
ranges;
//usbotg1: usb@02184000 {
compatible = "fsl,imx6ul-usb", "fsl,imx27-usb";
reg = <0x02184000 0x4000>;
status = "disabled";
};
}
//aips3节点
aips3: aips-bus@02200000 {
compatible = "fsl,aips-bus", "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
reg = <0x02200000 0x100000>;
ranges;
//rngb节点
rngb: rngb@02284000 {
compatible = "fsl,imx6sl-rng", "fsl,imx-rng", "imxrng";
reg = <0x02284000 0x4000>;
};
}
}
}
四、设备树在系统中的体现
Linux 内核启动的时候会解析设备树中各个节点的信息,并且在根文件系统的/proc/devicetree 目录下根据节点名字创建不同文件夹,如图所示
上图就是目录/proc/device-tree 目录下的内容, /proc/device-tree 目录下是根节点“/”的所有属性和子节点