嵌入式Linux驱动开发(四)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函数。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值