linux设备树
- 1、什么是设备树
- 2、DTS、DTB、DTC的关系
- 3、如何编译设备树
- 4、DTS基本结构
- 4.1、语法
- 4.2、设备树在系统中的体现
- 4.3、尝试自己添加节点
- 4.4、尝试对根节点追加信息
- 5、设备树特殊节点
- 5.1、chosen子节点
- 5.2、aliases子节点
- 6、设备树中标准属性
- 6.1、compatilbe属性
- 6.2、model属性
- 6.3、status属性
- 6.4、reg属性
- 6.5、#address-cells和#size-cells
- 7、OF操作函数
- 7.1、OF函数查找节点
- ① of_find_node_by_name
- ② of_find_compatible_node
- ③ of_find_node_by_path
- 7.2、查找父子节点的OF函数
- ① of_get_parent
- ② of_get_next_child
- 7.3、提取属性值的OF函数
- ① of_find_property
- ② of_property_read_u32_index
- ③ of_property_read_u8_array
- ④ of_property_read_u8
1、什么是设备树
设备树DTS(Device Tree Source),DTS文件用树形结构描述板级设备,也就是开发板上的设备信息,比如CPU数量,内存基地址,IIC接口上接了哪些设备等等,如下图:
2、DTS、DTB、DTC的关系
1、DTS是设备树的源文件
2、DTB是DTS编译后得到的二进制文件
3、DTC是DTS的编译工具,源码在内核的scripts/dtc目录下面,如下:
3、如何编译设备树
1、make dtbs:编译所有的dts文件;
2、make xxx.dts:编译指定的dts文件按;
4、DTS基本结构
设备树也有头文件,扩展名为.dtsi
4.1、语法
1、根节点:/
2、从/根节点开始描述设备信息
3、在/根节点外有一些&cpu0这样的语句是“追加”
这里以imx6ull-alientek-emmc.dts为例,下图chosen,memor为子节点
/dts-v1/;
#include <dt-bindings/input/input.h>
#include "imx6ull.dtsi"
/ {
model = "Freescale i.MX6 ULL 14x14 EVK Board";
compatible = "fsl,imx6ull-14x14-evk", "fsl,imx6ull";
chosen {
stdout-path = &uart1;
};
memory {
reg = <0x80000000 0x20000000>;
};
&cpu0 {
arm-supply = <®_arm>;
soc-supply = <®_soc>;
dc-supply = <®_gpio_dvfs>;
};
}
4、节点名字完整的要求:node-name@unit-address,例如:
i2c4: i2c@021f8000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl,imx6ul-i2c", "fsl,imx21-i2c";
reg = <0x021f8000 0x4000>;
interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX6UL_CLK_I2C4>;
status = "disabled";
};
后面0x021f8000为i2c4的起始地址。
5、还可以为节点加标签,在设备树也是很常见的,例如:
lable:node-name@unit-address
lable为标签,后面node-name是名字。加lable的目的是为了后面访问追加时方便。
4.2、设备树在系统中的体现
1、系统启动以后可以在根文件系统里面可以看到设备树节点信息,在/proc/device-tree/目录下存放着设备树信息,一级子节点。一级子节点内还有二级子节点。
4.3、尝试自己添加节点
1、在imx6ull-alientek-emmc.dts根节点下添加如下内容
2、make dtbs编译,拷贝到tftp目录下,重启开发板,进入到/proc/device-tree目录下即可看到添加的节点
4.4、尝试对根节点追加信息
1、添加之前intc节点目录内容如下:
2、在imx6ull-alientek-emmc.dts下加入如下内容
3、编译、拷贝、重启开发板,追加节点信息如下:
5、设备树特殊节点
5.1、chosen子节点
1、chosen并不是一个真实的节点,主要目的是将uboot里面的bootargs环境变量传递给linux内核,作为命令行参数。
uboot里面的bootargs为:
kernel中bootargs为:
2、经过查看chosen节点中包含bootargs属性,但是我们在设备树里面并没有设置bootargs。
3、这是因为在uboot过程中fdt_chosen函数会将bootargs传给内核,在uboot源码中common/fdt_support.c文件内,如下:
5.2、aliases子节点
aliaese的意思是 “别名” ,给节点起另一个名字。
6、设备树中标准属性
6.1、compatilbe属性
1、copatible属性叫做兼容性,值是一个字符串列表,compatible属性用来将设备和驱动绑定起来,其格式一般为“manufacturer,model”
。
2、在驱动中of_device_id机构提匹配表,保存着一些compatible值,如果设备节点的compatible属性值和of匹配表中的任何一个值相等,就会调用probe函数。
6.2、model属性
model属性值也是一个字符串,描述设备模块信息,比如名字:
model = "wm8960-audio";
6.3、status属性
状态
okay:表示设备可操作
disable:表示设备不可操作
6.4、reg属性
reg属性值一般是(address,length),描述设备地址空间资源,一般都是某个外设的寄存器地址范围信息,如:
uart1: serial@02020000 {
compatible = "fsl,imx6ul-uart","fsl,imx6q-uart", "fsl,imx21-uart";
reg = <0x02020000 0x4000>;
interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX6UL_CLK_UART1_IPG>,
<&clks IMX6UL_CLK_UART1_SERIAL>;
clock-names = "ipg", "per";
status = "disabled";
};
6.5、#address-cells和#size-cells
1、这两个属性值都是无符号32位整形。address-cells属性绝对了子节点reg属性中地址信息所占用的字长,size-cells属性值决定了子节点reg属性中长度信息所占用的字长。如:
spi4 {
compatible = "spi-gpio";
#address-cells = <1>;
#size-cells = <0>;
gpio_spi: gpio_spi@0 {
compatible = "fairchild,74hc595";
reg = <0>;
};
};
aips3: aips-bus@02200000 {
compatible = "fsl,aips-bus", "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
dcp: dcp@02280000 {
compatible = "fsl,imx6sl-dcp";
reg = <0x02280000 0x4000>;
};
};
2、spi4的address=1,size=1,说明spi4的子节点reg属性中起始地址所占用字长为1,地址长度所占用字长位0
3、gpio_spi: gpio_spi@0节点中的reg属性:reg = <0>,是因为父节点设置了address=1,size=0。
aips3也同样理解。
7、OF操作函数
1、在驱动中使用OF函数获取设备属性内容。设备都是以节点的形式挂到设备树上,因此要想获取这个设备的其他属性信息,必须先获取节点。
2、Linux内核使用device_node结构体来描述一个节点,此结构体定义在include/linux/of.h中。
7.1、OF函数查找节点
① of_find_node_by_name
struct device_node *of_find_node_by_name(struct device_node *from,const char *name);
参数:
1、form:开始查找的节点,如果为NULL表示从根节点开始查找整个设备树name:要查找的节点名字
2、返回值:找到的节点,如果为NULL表示查找失败
② of_find_compatible_node
参数:
1、from:开始查找的节点,如果为 NULL 表示从根节点开始查找整个设备树。
2、type:要查找的节点对应的 type 字符串,也就是 device_type 属性值,可以为 NULL,表示忽略掉 device_type 属性。
3、compatible: 要查找的节点所对应的 compatible 属性列表。
4、返回值: 找到的节点,如果为 NULL 表示查找失败
③ of_find_node_by_path
参数:
1、path:带有全路径的节点名,可以使用节点的别名,比如“/backlight”就是 backlight 这个节点的全路径。
2、返回值: 找到的节点,如果为 NULL 表示查找失败
7.2、查找父子节点的OF函数
参数就不介绍了,使用较少。
① of_get_parent
② of_get_next_child
7.3、提取属性值的OF函数
节点的属性信息里面保存了驱动所需要的内容,Linux内核中使用结构体property表示属性,此结构体定义在of.h文件中,如下:
struct property {
char *name;
int length;
void *value;
struct property *next;
unsigned long _flags;
unsigned int unique_id;
struct bin_attribute attr;
};
① of_find_property
该函数用于查找指定的属性,函数原型:
property *of_find_property(const struct device_node *np,const char *name,int *lenp)
参数介绍:
1、np:设备节点
2、name:属性名字
3、lenp:属性值的字节数
4、返回值:找到的属性
② of_property_read_u32_index
从属性中获取指定标号的u32类型数据值,函数原型如下:
int of_property_read_u32_index(const struct device_node *np,const char *propname,u32 index,u32 *out_value)
③ of_property_read_u8_array
读取属性中u8类型的数组数据,也可以读u16、u32、u64类型的,函数原型如下:
int of_property_read_u8_array(const struct device_node *np,const char *propname,u8 *out_values,size_t sz)
④ of_property_read_u8
读取之后一个整形值的属性,函数原型如下:
int of_property_read_u8(const struct device_node *np,const char *propname,u8 *out_value)
下篇使用OF函数获取设备树节点信息。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)