嵌入式Linux驱动开发(四)Linux设备树

  • Post author:
  • Post category:linux




1. 设备树概念

在这里插入图片描述

设备树源码文件(DTS)的作用就是按照图中的结构描述板级设备信息。老版本的linux种没有设备树,是按照arch/arm/mach-xxx和arch/arm/plat-xxx文件夹描述设备信息,结果就是导致内核文件很多。DTS编译之后得到的二进制文件就是DTB文件,编译工具为DTC。



2. DTS语法



2.1 .dtsi头文件及设备节点

dtsi头文件一般用于描述SOC的内部外设信息比如CPU架构,主频等。设备树上的每个设备都是一个设备节点,通过一些属性(Key-Value)描述节点信息。

设备节点命名格式:

①:

node-name@unit-address

——“节点名@设备地址或寄存器首地址,没有就是0”。

②:

label: node-name@unit-address

—–引入label可以通过&label访问节点。



2.2 DTS常用数据形式


①字符串:


比如“ compatible = “arm,cortex-a7” ”设置compatible属性值为”arm,cortex-a7″。


②32位无符号整数:


比如“reg = <0>”设置reg属性的值为0.


③字符串列表:


字符串值之间采用逗号隔开。



2.3 标准属性


①compatible:兼容性



值是字符串列表

,遵循“厂商,模块驱动”的格式,用于将设备和驱动绑定起来。比如:

compatible = "fsl,imx6ul-evk-wm8960","fsl,imx-audio-wm8960";

当WM8960设备寻找驱动时,首先使用第一个兼容值去找,没找到就下一个。在驱动文件种有

OF匹配表

,其中保存了一些兼容值,如果和设备节点的兼容值匹配上就表示设备可以使用该驱动。

<imx-wm8960.c的OF匹配表>
static const struct of_device_id imx_wm8960_dt_ids[] = {
	{ .compatible = "fsl,imx-audio-wm8960", },
	{ /* sentinel */ }
};


②model:设备信息



值是字符串

,用于描述设备模块信息比如名字之类。


③status:设备状态



值是字符串

,可选状态有:okay(设备可操作),disabled(设备暂时不可操作),fail(设备不可操作),fail-sss(设备不可操作,sss是错误信息)。


④#address-cells 和#size-cells:



值是u32t

,用于描述子节点地址信息。前者决定子节点reg属性中

起始地址

信息占用字长,后者决定子节点reg属性中

地址长度

信息所占字长。


⑤reg:



reg属性一般和地址有关,包括起始地址和地址长度

。值为“address-length”对。


⑥ranges:地址映射表


可以为空,或者是(

子地址,父地址,地址空间长度

)格式的数字矩阵。在I.MX6ULL中子地址空间和父地址空间完全相同,所以经常会有空的ranges属性。

child-bus-address:
<子总线地址空间的物理地址,由父节点的#address-cells 确定此物理地址所占用的字长>
parent-bus-address:
<父总线地址空间的物理地址,同样由父节点的#address-cells 确定此物理地址所占用的字长>
length:
<子地址空间的长度,由父节点的#size-cells 确定此地址长度所占用的字长>



2.4 根节点的兼容性属性

compatible = "fsl,imx6ull-14x14-evk", "fsl,imx6ull";

根节点的兼容性属性一般第一个值是描述设备名,第二个值是描述设备使用的SOC。


Q1:Linux内核使用设备树,如何判断是否支持某一设备:


内核定义了一个DT_MACHINE_START宏,用于定义machine_desc结构体描述设备。这个结构体中有一个.dt_compat成员变量,经过和根节点compatible属性值对比,有就代表兼容。


Q2:machine_desc结构体匹配根节点compatible属性的流程:


在这里插入图片描述

start_kernel                      <---1.启动内核>
	setup_arch                    <---2.匹配machine_desc结构体>
		<获取匹配的machine_desc>
		setup_machine_fdt: of_flat_dt_match_machine
			<获取设备树根节点>
			of_get_flat_dt_root   



2.5 向节点追加数据


要求:向i2c1节点追加一个fxls8471子节点,不能影响到其它使用I.MX6ULL的板子。



方法:在imx6ull-alientek-emmc.dts中找到&i2c1这个label,通过该label访问.dtsi中对应的节点。



3. 创建小型模板设备树

需要在设备树描述以下内容:

①I.MX6ULL 这个 Cortex-A7 架构的 32 位 CPU。

②I.MX6ULL 内部 ocram,起始地址 0x00900000,大小为 128KB(0x20000)。

③I.MX6ULL 内部 aips1 域下的 ecspi1 外设控制器,寄存器起始地址为 0x02008000,大小为 0x4000。

④I.MX6ULL 内部 aips2 域下的 usbotg1 外设控制器,寄存器起始地址为 0x02184000,大小为 0x4000。

⑤I.MX6ULL 内部 aips3 域下的 rngb 外设控制器,寄存器起始地址为 0x02284000,大小为 0x4000。


步骤:


1)创建myfirst.dts文件,设置根节点compatible属性。

2)添加CPUs节点。

3)添加SOC节点,作为父节点管理众多SOC外设对应的子节点。

4)添加ocram节点。内部RAM,属于SOC的子节点。起始地址0x00900000,大小128KB-0x20000。

5)添加aips123这三个子节点。6ULL的内部分为三个域aips1-3,分管不同的外设控制器。SOC子节点。

6)添加ecspi1,usbotg1,rngb三个外设控制节点。



4. 设备树在系统中的体现及特殊节点

内核启动后,在rootfs的/proc/device-tree目录下为根节点的所有属性和子节点。根节点属性也以文件类型表示,打开后就是属性值。


特殊节点:



1)aliases子节点:


用于定义别名,方便访问节点。

aliases {
	can0 = &flexcan1;
	can1 = &flexcan2;
	...
};


2)chosen子节点:


为了uboot向linux内核传递数据,重点是bootargs参数,该属性不会在代码中出现,但是可以通过ls命令查看到。这个参数是在内核启动时,do_bootm_linux函数指挥是boot通过fdt_chosen这个函数传递进来的。

在这里插入图片描述



5. 内核解析DTB文件的流程

在这里插入图片描述

当我们需要添加节点时,可以通过内核源码中的/Documentation/devicetree/bindings下的.txt绑定文档查看帮助。



6. 设备树常用OF操作函数

用于获取设备树中的节点或者属性信息的函数,统一前缀“of_”,称为OF函数,定义在include/linux/of.h中。



6.1 查找节点的OF函数

内核使用device_node结构体描述一个节点。相关OF函数如下:

1)of_find_node_by_name:通过节点名查找。

2)of_find_node_by_type:通过device_type属性查找。

3)of_find_compatible_node:通过device_type和compatible属性查找。

4)of_find_matching_node_and_match:通过of_device_id匹配表查找。

5)of_find_node_by_path:通过带节点名的全路径(可以使用别名)查找。



6.2 查找父/子节点的OF函数

1)of_get_parent:获取父节点。

2)of_get_next_child :获取子节点。



6.3 提取属性值的OF函数

内核使用

property结构体

表示属性。

1)of_find_property:查找指定属性。

2)of_property_count_elems_of_size:获取属性中元素的数量。

3)of_property_read_u32_index:从属性中获取指定标号的 u32 类型数据值。

4)of_property_read_u8/16/62/64_array:读取属性中 u8、u16、u32 和 u64 类型的数组数据。

5)of_property_read_u8/16/62/64:读取属性中 u8、u16、u32 和 u64 类型的整形数据。

6)of_property_read_string:读取属性中字符串值。

7)of_n_addr_cells:读取#address-cells值。

8)of_n_size_cells:读取#size-cells值。



6.4 其它常用OF函数

1)of_device_is_compatible:查看节点compatible属性是否包含指定的字符串。用于检查兼容性。

2)of_get_address:获取地址相关属性。

3)of_translate_address:将从设备树独到的地址转化为物理地址。

4)of_address_to_resource:将reg属性值转换为resource结构体类型。该结构体用于描述设备资源信息。

5)of_iomap:直接内存映射,作用等同于ioremap函数。



版权声明:本文为qq_41075961原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。