设备树
1、什么是设备树
设备树(Device Tree),将这个词分开就是“设备”和“树”,描述设备树的文件叫做 DTS(Device Tree Source),这个 DTS 文件采用树形结构描述板级设备,也就是开发板上的设备信息,比如CPU 数量、 内存基地址、 IIC 接口上接了哪些设备、 SPI 接口上接了哪些设备等等。
设备树描述板级信息,设备信息的文件,dts结尾
2、DTS、DTB、DTC
make dtds
.dts是DTS源码文件,DTC(在/scripts/dtc)相当于编译器,将.dts编译成.dtb
3、基本结构
(1)头文件
和 C 语言一样,设备树也支持头文件,设备树的头文件扩展名为.dtsi。一般.dtsi 文件用于描述通用SOC 的内部外设信息,比如 CPU 架构、主频、外设寄存器地址范围,比如 UART、 IIC 等等。
(2)设备节点
1 / { 2 aliases { 3 can0 = &flexcan1; 4 }; 5 6 cpus { 7 #address-cells = <1>; 8 #size-cells = <0>; 9 10 cpu0: cpu@0 { 11 compatible = "arm,cortex-a7"; 12 device_type = "cpu"; 13 reg = <0>; 14 }; 15 }; 16 17 intc: interrupt-controller@00a01000 { 18 compatible = "arm,cortex-a7-gic"; 19 #interrupt-cells = <3>; 20 interrupt-controller; 21 reg = <0x00a01000 0x1000>, 22 <0x00a02000 0x100>; 23 }; 24 }
设备树是采用树形结构来描述板子上的设备信息的文件,每个设备都是一个节点,叫做设备节点,每个节点都通过一些属性信息来描述节点信息,属性就是键—值对。
第一行中“/”表示根节点,每个设备树只有一个根节点。
aliases、 cpus 和 intc 是三个子节点
node-name@unit-address
node-name”是节点名字, “unit-address”一般表示设备的地址或寄存器首地址,如果某个节点没有地址或者寄存器的话“unit-address”可以不要,比如“cpu@0”、“interrupt-controller@00a01000”。
label: node-name@unit-address
引入 label 的目的就是为了方便访问节点,可以直接通过&label 来访问这个节点,比如通过&cpu0 就可以访问“cpu@0”这个节点。
(3)属性
(a)compatible属性
compatible 属性的值是一个字符串列表, compatible 属性用于将设备和驱动绑定起来。字符串列表用于选择设备所要使用的驱动程序, compatible 属性的值格式如下所示:
"manufacturer,model" //其中 manufacturer 表示厂商, model 一般是模块对应的驱动名字。
一般驱动程序文件都会有一个 OF 匹配表,此 OF 匹配表保存着一些 compatible 值,如果设备节点的 compatible 属性值和 OF 匹配表中的任何一个值相等,那么就表示设备可以使用这个驱动。
(b)model属性
一般 model 属性描述设备模块信息。
(c)status属性
okay、disable、fail、fail-ass。
(d)address-cells和size-cells属性
描述子节点的地址信息。 #address-cells 属性值决定了子节点 reg 属性中地址信息所占用的字长(32 位), #size-cells 属性值决定了子节点 reg 属性中长度信息所占的字长(32 位)。 #address-cells 和#size-cells 表明了子节点应该如何编写 reg 属性值。
(f)status
描述设备状态:okay:设备可操作性。disable:设备当前是不可操作的,但是在未来可以变为可操作的,比如热插拔设备插入后,fai:设备有错误。fail-sss:设备有错,后面接错误内容。
(e)alisaes
aliases 节点的主要功能就是定义别名,定义别名的目的就是为了方便访问节点。不过一般会在节点命名的时候会加上 label,然后通过&label来访问节点,这样也很方便,而且设备树里面大量的使用&label 的形式来访问节点。
4、内核解析DTB
Linux 内核在启动的时候会解析 DTB 文件,然后在/proc/device-tree 目录下生成相应的设备树节点文件。

5、OF操作函数
(1)常见查找函数
1、 of_find_node_by_name 函数
struct device_node *of_find_node_by_name(struct device_node *from, const char *name); //from:开始查找的节点,如果为 NULL 表示从根节点开始查找整个设备树。 //name:要查找的节点名字。 //返回值: 找到的节点,如果为 NULL 表示查找失败。
2、 of_find_node_by_type 函数
struct device_node *of_find_node_by_type(struct device_node *from, const char *type) //from:开始查找的节点,如果为 NULL 表示从根节点开始查找整个设备树。 //type:要查找的节点对应的 type 字符串,也就是 device_type 属性值。 //返回值: 找到的节点,如果为 NULL 表示查找失败。
3、 of_find_compatible_node 函数
struct device_node *of_find_compatible_node(struct device_node *from, const char *type, const char *compatible) //from:开始查找的节点,如果为 NULL 表示从根节点开始查找整个设备树。 //type:要查找的节点对应的 type 字符串,也就是 device_type 属性值,可以为 NULL,表示忽略掉 device_type 属性。 //compatible: 要查找的节点所对应的 compatible 属性列表。 //返回值: 找到的节点,如果为 NULL 表示查找失败
4、 of_find_matching_node_and_match 函数
struct device_node *of_find_matching_node_and_match(struct device_node *from, const struct of_device_id *matches, const struct of_device_id **match) //from:开始查找的节点,如果为 NULL 表示从根节点开始查找整个设备树。 //matches: of_device_id 匹配表,也就是在此匹配表里面查找节点。 //match: 找到的匹配的 of_device_id。 //返回值: 找到的节点,如果为 NULL 表示查找失败
5、 of_find_node_by_path 函数
inline struct device_node *of_find_node_by_path(const char *path) //path:带有全路径的节点名 //返回值: 找到的节点,如果为 NULL 表示查找失败
(2)提取属性值
Linux 内核中使用结构体 property 表示属性
1、 of_find_property 函数
property *of_find_property(const struct device_node *np, const char *name, int *lenp) //np:设备节点。 //name: 属性名字。 //lenp:属性值的字节数
2、 of_property_count_elems_of_size 函数
用于获取属性中元素的数量
3、of_property_read_
读取属性中值
(3)其他的OF
1、 of_device_is_compatible 函数
查看节点中是否有compat
int of_device_is_compatible(const struct device_node *device, const char *compat) //device:设备节点。 //compat:要查看的字符串。
2、 of_get_address 函数
const __be32 *of_get_address(struct device_node *dev, int index, u64 *size, unsigned int *flags) //dev:设备节点。 //index:要读取的地址标号。 //size:地址长度。 //flags:参数,比如 IORESOURCE_IO、 IORESOURCE_MEM 等
3、of_iomap 函数
用于直接内存映射

浙公网安备 33010602011771号