设备树(DT)是一个易于阅读的硬件描述文件,具有类似json的格式化风格,这是一个简单的树结构,其中设备由节点及其属性表示。属性可以为空(仅有key,用于描述布尔值),也可以为key-value对,其中value可以包含任意字节流。本章是对DT的简单介绍。每个内核子系统或框架都有自己的DT绑定。我们将在讨论相关主题时讨论这些特定的绑定。dt起源于OF, OF是计算机公司认可的标准,其主要目的是为计算机固件系统定义接口。也就是说,您可以在http://www.devicetree.org/上找到更多关于DT规范的信息。本文将介绍DTs的基础知识,例如:
- 命名约定,以及别名和标签
- 描述数据类型及其APIs
- 地址方案管理和设备资源访问
- 实现OF匹配样式并提供特定于应用程序的数据
设备树机制
通过将CONFIG_OF选项设置为y,可以在内核中启用DT。为了从驱动程序中使用DT API,必须添加以下头文件:
#include <linux/of.h> #include <linux/of_device.h>
DT支持几种数据类型。下面用一个示例节点描述来看看它们:
/* This is a comment */ // This is another comment node_label: nodename@reg{ string-property = "a string"; string-list = "red fish", "blue fish"; one-int-property = <197>; /* One cell in this property */ int-list-property = <0xbeef 123 0xabcd4>; /*each number(cell)is a 32 bit integer(uint32). There are 3 cells in this property*/ mixed-list-property = "a string", <0xadbcd45>, <35>, [0x01 0x23 0x45] byte-array-property = [0x01 0x23 0x45 0x67]; boolean-property; };
以下是DTs中使用的数据类型的一些定义:
- 文本字符串用双引号表示。可以使用逗号创建字符串列表。
- cell是由尖括号分隔的32位无符号整数。
- 布尔数据只是一个空属性。值的真或假取决于属性是否存在。
命名约定
每个节点必须有一个<name>[@<address>]形式的名称,其中<name>是一个最多31个字符的字符串,[@<address>]是可选的,取决于节点是否表示可寻址设备。<address>应是用于访问设备的主地址。设备命名举例如下:
expander@20 { compatible = "microchip,mcp23017"; reg = <20>; [...] };
下面是另一个例子:
i2c@021a0000 { compatible = "fsl,imx6q-i2c", "fsl,imx21-i2c"; reg = <0x021a0000 0x4000>; [...] };
另一方面,标签(label)是可选的。只有当一个节点的属性打算被另一个节点引用时,标记该节点才有用。您可以将标签视为指向节点的指针,这将在下文中解释。
Aliases, labels 和 phandle
理解这三个元素是如何工作的是非常重要的。它们经常用于DTs。下面就让DT君来解释一下它们的工作原理:
aliases { ethernet0 = &fec; gpio0 = &gpio1; gpio1 = &gpio2; mmc0 = &usdhc1; [...] }; gpio1: gpio@0209c000 { compatible = "fsl,imx6q-gpio", "fsl,imx35-gpio"; [...] }; node_label: nodename@reg { [...]; gpios = <&gpio1 7 GPIO_ACTIVE_HIGH>; };
标签只是标记节点的一种方法,让节点由唯一的名称标识。在现实世界中,DT编译器将该名称转换为唯一的32位值。在上面的例子中,gpio1和node_label都是标签。然后可以使用标签来引用节点,因为标签对于节点是唯一的。指针句柄(phandle)是一个与节点关联的32位值,用于唯一标识该节点,以便可以从另一个节点中的属性引用该节点。标签用于有一个指向节点的指针。通过使用<&mylabel>,可以指向其标签为mylabel的节点。
&的使用就像在C编程语言中一样,获取元素的地址。
在前面的示例中,&gpio1被转换为一个phandle,它指向gpio1节点。下面的例子也是一样:
thename@address { property = <&mylabel>; }; mylabel: thename@adresss { [...] }
为了不遍历整个树来查找节点,引入了别名的概念。在DTs中,可以将别名节点视为快速查找表,即另一个节点的索引。可以使用find_node_by_alias()函数查找给定别名的节点。在DT源代码中并没有直接使用别名,而是由Linux内核加以引用。
DT编译器
DT有两种形式:文本形式(表示源代码,也称为DTS)和二进制blob形式(表示编译后的DT,也称为DTB)。源文件扩展名为.dts。实际上,还有.dtsi文本文件,表示SoC级别的定义,而.dts文件表示板卡级别的定义。您可以看到.dtsi作为头文件应该包含在.dts文件中,有点像在源文件(.c)中包含头文件(.h)。另一方面,二进制文件使用.dtb扩展名。
实际上还有第三种形式,即DT的运行时表示形式/proc/device-tree。
顾名思义,用于编译设备树的工具称为设备树编译器(dtc)。从根内核源代码可以编译一个独立的特定DT,也可以编译特定体系结构的所有DT。
让我们编译ARM soc的所有DT (.dts)文件:
ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- make dtbs
这是针对独立DT的:
ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- make imx6dl-sabrelite.dtb
在此例中,源文件名为“imx6dl-sabrelite.dts”。
给定一个已编译的设备树(.dtb)文件,您可以执行相反的操作并提取源文件(.dts):
dtc -I dtb -O dts -o xxx.dts arch/arm/boot/dts/imx6dl-sabrelite.dtb
出于调试的目的,向用户空间公开DT可能很有用。CONFIG_PROC_DEVICETREE配置变量将为您完成这一工作。然后,您可以在/proc/device-tree中探索和遍历DT。
标签:标签,DT,概念,dts,机制,property,节点,设备 From: https://www.cnblogs.com/wanglouxiaozi/p/17195703.html