二十二、【devicetree】设备树的介绍
一、简介
设备树定义是保留着存在于系统中的设备信息,当机器引导时,OS通过使用驱动程序和其他组件获得的信息建立此树,并且当添加或删除设备时更新此树。
- 设备树保留着存在于系统中的设备信息。当机器引导时,OS通过使用驱动程序和其他组件获得的信息建立此树,并且当添加或删除设备时更新此树。
- 设备树是分级的, 总线上的设备代表着总线适配器或驱动控制器的“子集”。
- 设备树的每一个节点是一个设备节点(devnode),一个devnode包括设备驱动程序的设备对象加上有OS所保留的内部信息。
- DTS:设备树源文件,ASCII格式
- DTC:设备树编译工具。
- DTB:二进制设备树。
二、设备树的使用
uboot负责加载到内存,内核解析使用。
1、编译
//内核编译dts
make ARCH=arm -j4 CROSS_COMPILE=arm-linux-gnueabihf- dtbs
//手工编译
./scripts/dtc/dtc -I dts -O dtb -o xxx.dtb arch/arm/boot/dts/xxx.dts // 编译 dts 为 dtb
./scripts/dtc/dtc -I dtb -O dts -o xxx.dts arch/arm/boot/dts/xxx.dtb // 反编译 dtb 为 dts
2、设备树常见属性介绍
(1)节点属性
cpu0: cpu@0 {
compatible = "arm,cortex-a7";
device_type = "cpu";
reg = <0>;
}
- cpu0:为结点名称起一个别名。
(2)compatible属性
intc: interrupt-controller@a01000 {
compatible = "arm,cortex-a7-gic";
#interrupt-cells = <3>;
interrupt-controller;
reg = <0xa01000 0x1000>,
<0xa02000 0x100>;
};
- arm:芯片厂商。
- cortex-a7-gic:模块对应的驱动名
(3)model属性
model = "embedfire i.MX6 ULL NPi Board";
- 准确描述当前板子型号信息。
(4)status属性
(5)reg属性
ocrams: sram@900000 {
compatible = "fsl,lpm-sram";
reg = <0x900000 0x4000>;
};
- 地址:外设寄存器组的起始地址。
- 长度:外设寄存器组的字节长度。
(6)#address-cells和#size-cells属性
soc {
#address-cells = <1>;
#size-cells = <0>;
compatible = "simple-bus";
interrupt-parent = <&gpc>;
ranges;
ocrams: sram@900000 {
compatible = "fsl,lpm-sram";
reg = <0x900000>;
};
};
- #address-cells:设置子节点reg地址的数量 。
- #size-cells:设置子节点中reg地址的长度的数量。
3、系统中查看设备树
ls /sys/firmware/devicetree/base
或者:
ls /proc/device-tree
4、驱动中获取DTS属性信息的接口
(1)节点表示:/include/linux/of.h
struct device_node {
const char *name; //节点名
const char *type; //设备类型
phandle phandle;
const char *full_name; //完整名字
struct fwnode_handle fwnode;
struct property *properties; //属性
struct property *deadprops;
struct device_node *parent; //父节点
struct device_node *child; //子节点
struct device_node *sibling;
#if defined(CONFIG_OF_KOBJ)
struct kobject kobj;
#endif
unsigned long _flags;
void *data;
#if defined(CONFIG_SPARC)
const char *path_component_name;
unsigned int unique_id;
struct of_irq_controller *irq_trans;
#endif
};
-
路径/类型/名字/compatible
incldue/linux/of.h
(2)of_find_node_by_path()函数
struct device_node *of_find_node_by_path(struct device_node *from,const char *path);
参数:
-
from:开始查找的节点,NULL表示从根节点开始查找
-
path:查找的节点名
返回值:
- 成功:device_node表示的节点
- 失败:NULL
(3)of_find_node_by_type()函数:根据“device_type“属性来查找节点
struct device_node *of_find_node_by_type(struct device_node *from, const char *type);
不建议使用
(4)of_find_node_by_name()函数:根据"name"属性来查找节点
struct device_node *of_find_node_by_name(struct device_node *from,const char *name);
不建议使用
(5)of_find_compatible_node()函数
struct device_node *of_find_compatible_node(struct device_node *from,const char *type, const char *compat);
参数:
-
from:开始查找的节点,NULL表示从根节点开始查找
-
type:指定 device_type 属性值
-
compat:指定 compatible 属性值
返回值:
- 成功:device_node表示的节点
- 失败:NULL
(4)查节点的属性值:incldue/linux/of.h
struct property {
char *name; //属性名
int length; //属性长度
void *value; //属性值
struct property *next; //下一个属性
#if defined(CONFIG_OF_DYNAMIC) || defined(CONFIG_SPARC)
unsigned long _flags;
#endif
#if defined(CONFIG_OF_PROMTREE)
unsigned int unique_id;
#endif
#if defined(CONFIG_OF_KOBJ)
struct bin_attribute attr;
#endif
};
(5)of_find_property()函数
-
节点+属性名
查找节点中的属性
struct property *of_find_property(const struct device_node *np,const char *name,int *lenp);
参数:
-
np:device_node表示的节点
-
name:查找的属性名字
-
lenp:属性值的字节数
返回值:
- 成功:property表示的属性
- 失败:NULL
(6)of_property_read_u32()函数:读取一个32位无符号整数
static inline int of_property_read_u32(const struct device_node *np,const char *propname,
u32 *out_value);
参数:
-
np:device_node表示的节点
-
propname:查找的属性名字
-
out_value:属性值的整数值
返回值:
- 成功:0
- 失败:负值
(7)of_property_read_u32_array()函数:读取32位无符号整数数组
int of_property_read_u32_array(const struct device_node *np,const char *propname,u32 *out_values,size_t sz)
-
np:device_node表示的节点
-
name:查找的属性名字
-
out_value:读取到的数组值
-
sz :要读取的数组元素数量
(8)of_property_read_string()函数:读字符串
int of_property_read_string(struct device_node *np,const char *propname,const char **out_string)
参数:
-
np:device_node表示的节点
-
proname:查找的属性名字
-
out_string:读取到的字符串值
返回值:
- 成功:0
- 失败:负值