设备树和设备树语法

news2024/12/24 2:28:28

设备树

驱动代码只负责处理驱动的逻辑,而关于设备的具体信息存放到设备树文件中。许多硬件设备信息可以直
接通过它传递给 Linux,而不需要在内核中堆积大量的冗余代码。
设备树,将这个词分开就是“设备”和“树”,描述设备树的文件叫做 DTS(Device Tree Source),这个 DTS 文件采用树形结构描述板级设备,也就是开发板上的硬件设备信息,比如CPU 数量、内存基地址、IIC 接口上接了哪些设备、SPI 接口上接了哪些设备等等。
在这里插入图片描述
设备树文件的扩展名为 .dts,一个 .dts(device tree source)就文件对应一个开发板。该文件放置在内核的"arch/arm/boot/dts/"目录下,zynq开发板的板级设备树文件就是arch/arm/boot/dts/system-top.dts。上述文件是使用hsi命令生成的,除了system-top.dts文件还生成了另外三个文件pl.dtsi,pcw.dtsi,zynq-7000.dtsi。
pl.dtsi 在 vivado 当中添加的 pl 端外设对应的配置信息
pcw.dtsi 在 vivado 当中已经使能的 PS 外设
zynq- 7000.dtsi zynq-7000 系列处理器相同的硬件外设配置信息(PS 端的)

部分文件后缀讲解

dts

设备树的源文件的后缀名就是.dts,每一款硬件平台可以单独写一份该后缀的文件。

dtsi

值得一提的是,对于一些相同的 dts 配置可以抽象到 dtsi 文件中,这个 dtsi 文件其实就类似于 C 语言当中的.h 头文件,可以通过 C 语言中使用 include 来包含一个.dtsi 文件。

dtc

dtc 其实就是 device-tree-compiler,那就是设备文件.dts 的编译器。
xilinx_zynq_defconfig(arch/arm/configs/xilinx_zynq_defconfig)文件就是我们 zynq平台对应的 defconfig 配置文件。

dtb

该文件是将dts文件编译后生成的二进制文件。

设备树结构

设备树用树状结构描述设备信息,组成设备树的基本单元是 node(设备节点),这些
node 被组织成树状结构,有如下一些特征:
➢ 一个 device tree 文件中只有一个 root node(根节点);
➢ 除了 root node,每个 node 都只有一个 parent node(父节点);
➢ 一般来说,开发板上的每一个设备都能够对应到设备树中的一个 node;
➢ 每个 node 中包含了若干的 property-value(键-值对,当然也可以没有 value)来描述该 node 的一些
特性;
➢ 每个 node 都有自己的 node name(节点名字);
➢ node 之间可以是平行关系,也可以嵌套成父子关系,这样就可以很方便的描述设备间的关系;

 /{ // 根节点
 		node1{ // node1 节点
 			property1=value1; // node1 节点的属性 property1
 			property2=value2; // node1 节点的属性 property2
 			...
 		}; 
 
 		node2{ // node2 节点
 			property3=value3; // node2 节点的属性 property3
			...
			node3{ // node2 的子节点 node3
				property4=value4; // node3 节点的属性 property4
				...
			}; 
		}; 
}

节点与属性

[label:]node-name[@unit-address] {
	[properties definitions]
	[child nodes]
};

label 是方便在dts文件中被其他节点引用;
node-name 为节点名称;
unit-address一般表示设备的地址或寄存器基地址;

设备树中值的属性

1)字符串

compatible = "arm,cortex-a9";

字符串使用双引号括起来,例如上面的这个 compatible 属性的值是” arm,cortex-a9” 字符串。
2)32 位无符号整形数据

clock-latency = <1000>;
reg = <0x00000000 0x00500000>;

32 位无符号整形数据使用尖括号括起来,例如属性 cock-latency 的值是一个 32 位无符 号整形数据 1000,而 reg 属性有两个数据,使用空格隔开,那么这个就可以认为是一个数组
3)二进制数据

local-mac-address = [00 0a 35 00 1e 53];

二进制数据使用方括号括起来,例如上面这个就是一个二进制数据组成的数组。
4)字符串数组

compatible = "n25q512a","micron,m25p80";

属性值也可以使用字符串列表,例如上面的这个属性,它的值是一个字符串列表,字符串之间使用逗号分割;
5)混合值

mixed-property = "a string", [0x01 0x23 0x45 0x67], <0x12345678>;

除此之外不同的数据类型还可以混合在一起,以逗号分隔。
6)节点引用

clocks = <&clkc 3>;

这其实就是我们上面说到的引用节点的一种形式,”&clkc”就表示引用”clkc”这个节点,而 clkc 就是前面提到的”label”,引用节点也是使用尖括号来表示,关于节点之间的引用,我们后面还会再讲,这里先告一段落。

标准属性

compatible属性

compatible 属性也叫做“兼容性”属性,一般该字符串使用“<制造商>,<型号>”这样的形式进行命名。compatible属性用于将设备和驱动绑定起来,然后会按照每个兼容值在Linux内核里查找。
补充:一般驱动程序文件都会有一个OF匹配表,此OF匹配表保存着一些compatible值,如果设备树中的节点的compatible属性值和OF匹配表中的任何一个值相等,则表明设备可以使用该驱动。

model属性

model属性值也是一个字符串描述信息,它指定制造商的设备型号,该属性一般定义在根节点下,一般就是对板子的描述信息,没啥实质性的作用。

status属性

status属性标志了设备的状态,使用status属性可以禁止设备或者启用设备,status可选值规范:

描述
okay表明设备是可操作的。启动设备
disabled表明设备当前是不可操作的,但在未来可以变为可操作的,
fail设备不可操作,设备检测到了一系列的错误
fail-sss含义与“fail”相同,后面的sss部分是检测到的错误内容

#address-cells 和 #size-cells 属性

这两个属性的值都是无符号32位整形,address-cells和size-cells这两个属性可以用在任何拥有子节点的设备节点中,用于描述子节点的地址信息。
➢ #address-cells,用来描述子节点"reg"属性的地址表中用来描述首地址的 cell 的数量
➢ #size-cells,用来描述子节点"reg"属性的地址表中用来描述地址长度的 cell 的数量
#address-cells 和#size-cells 表明了子节点应该如何编写 reg 属性值,reg属性都是和地址有关的内容,reg属性的格式一为:

reg = <address1 length1 address2 length2 address3 length3……>

每个“address length”组合表示一个地址范围,其中 address 是起始地址,length 是地址长度,#address-cells 表明 address 字段占用的字长,#size-cells 表明 length 这个字段所占用的字长

reg属性

reg 属性一般用于描述设备地址空间资源信息,一般都是描述某个外设的寄存器地址范围信息flash 设备
的分区信息等。

ranges属性

ranges 属性值可以为或者按照(child-bus-address,parent-bus address,length)格式编写的数字矩阵

fpga_full: fpga-full {
	compatible = "fpga-region";
	fpga-mgr = <&devcfg>;
	#address-cells = <1>;
	#size-cells = <1>;
	ranges;
};
//ranges的数值为空,则表示fpga_full:fpga-full节点的空间与父节点空间相同
 soc{ 
 	compatible = "simple-bus"; 3 #address-cells = <1>;
 	#size-cells = <1>;
 	ranges = <0x0 0xe0000000 0x00100000>;
 
 	serial{ 
 		device_type = "serial"; 
        compatible = "ns16550";
 		reg = <0x4600 0x100>;
 		clock-frequency = <0>;
 		interrupts = <0xA 0x8>;
 		interrupt-parent = <&ipic>;
 	};
 };

//第 4行,节点 soc 定义的 ranges 属性,值为<0x0 0xe0000000 0x00100000>,此属性值指定了一个 1024KB(0x00100000)的地址范围,子地址空间的物理起始地址为 0x0,父地址空间的物理起始地址为 0xe0000000。 
//第 9行,serial 是串口设备节点,reg 属性定义了 serial 设备寄存器的起始地址为0x4600,寄存器长度为 0x100。经过地址转换,serial 设备可以从 0xe0004600 开始进行读写操作,0xe0004600=0x4600+0xe0000000。

device_type 属性

device_type属性值为字符串,表示节点的类型;

特殊节点

根目录下的几个特殊节点

aliases节点

aliases {
	ethernet0 = &gem0;
	i2c0 = &i2c_2;
	i2c1 = &i2c0;
	i2c2 = &i2c1;
	serial0 = &uart0;
	serial1 = &uart1;
	spi0 = &qspi;
};

aliases 节点的主要功能就是定义别名,定义别名的目的就是为了方便访问节点。但是需要注意的是,这里说的方便访问节点并不是在设备树中访问节点,例如前面说到的使用“&label”的方式访问设备树中的节点,而是内核当中
方便定位节点

chosen节点

chosen 节点一般会有两个属性,“bootargs”和“stdout-path”。打开 system top.dts 文件,找到 chosen 节点,内容如下所示

绑定文档

绑定文档主要就是提供不同控制器或者硬件设备树属性描述的参考。如果在绑定文档中没有的外设芯片则需要向开发商索要设备树的参考属性,若开发商没有则不选择该型号芯片。部分外设的设备树属性参考可以在(/Documentation/devicetree/bindings)中找到。

根目录compatible属性

在设备树没有设备树之前,uboot会向Linux内核传递一个叫做machine id的值,告诉内核自己是谁,Linux内核会查看是否支持。
Linux内核引入设备树以后就不再使用machine id了,而是换为了dt machine start。设备树根节点的compatible,其中的参数会在imx6ul_dt_compat 表里面去寻找是否有匹配的参数,如果有表示内核可以在此芯片上运行,没有则无法运行。

OF操作函数

设备都是以节点的形式“挂”到设备上,因此当需要获取设备树中的某个节点具体的值的时候,需要先找到该节点。

查找节点的OF函数

/*
@description:通过节点名字查找指定的节点
@pararm-from:开始查找的节点,如果从根目录开始可以用NULL表示
@pararm-name:要查找的节点名称
*/
struct device_node *of_find_node_by_name(struct device_node *from,const char *name);

/*
@description:函数通过 device_type 属性查找指定的节点
@pararm-from:开始查找的节点,如果为 NULL 表示从根节点开始查找整个设备树
@pararm-type:要查找的节点对应的 type 字符串,也就是 device_type 属性值
*/
struct device_node *of_find_node_by_type(struct device_node *from, const char *type)
    
/*
@description:函数根据 device_type 和 compatible 这两个属性查找指定的节点
@pararm-from:开始查找的节点,如果为 NULL 表示从根节点开始查找整个设备树
@pararm-type:要查找的节点对应的 type 字符串,也就是 device_type 属性值,可以为 NULL,表示忽略掉 device_type 属性
@pararm-compatible:要查找的节点所对应的 compatible 属性列表
*/
struct device_node *of_find_compatible_node(struct device_node *from,const char *type, const char 														*compatible)
/*
@description:通过 of_device_id 匹配表来查找指定的节点
@pararm-from:开始查找的节点,如果为 NULL 表示从根节点开始查找整个设备树
@pararm-matches:of_device_id 匹配表,也就是在此匹配表里面查找节点
@pararm-match:找到的匹配的 of_device_id
*/
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)
    
/*
@description:通过路径来查找指定的节点
@pararm-path:带有全路径的节点名,可以使用节点的别名,比如“/backlight”就是 backlight 这个节点的全路径
*/
inline struct device_node *of_find_node_by_path(const char *path)
    

查找父/子节点的OF函数

/*
@description:用于获取指定节点的父节点(如果有父节点的话)
@pararm-node:要查找的父节点的节点
*/
struct device_node *of_get_parent(const struct device_node *node)
    
/*
@description:用迭代的方式查找子节点
@pararm-node:父节点
@pararm-prev:前一个子节点,也就是从哪一个子节点开始迭代的查找下一个子节点。可以设置为NULL,表示从第一个子节点开始
*/
struct device_node *of_get_next_child(const struct device_node *node,struct device_node *prev)

提取属性值的OF函数

节点的属性信息里面保存了驱动所需要的内容,因此对于属性值的提取非常重要,Linux内核中使用结构体property表示属性,此结构体同样定义在文件Include/linux/of.h中。

/*
@description:用于查找指定的属性
@pararm-np:设备节点
@pararm-name: 属性名字
@pararm-lenp:属性值的字节数
*/
property *of_find_property(const struct device_node *np,const char *name,int *lenp)

/*
@description:用于获取属性中元素的数量
@pararm-np:设备节点
@pararm-proname: 需要统计元素数量的属性名字
@pararm-elem_size:元素长度
return:得到的属性元素数量
*/
int of_property_count_elems_of_size(const struct device_node *np,const char *propname,int elem_size)

/*
@description:数用于从属性中获取指定标号的 u32 类型数据值(无符号 32 位)
@pararm-np:设备节点
@pararm-proname: 要读取的属性名字
@pararm-index:要读取的值标号
@pararm-out_value:读取到的值
return:0 读取成功,负值,读取失败,-EINVAL 表示属性不存在,-ENODATA 表示没有要读取的数据,-EOVERFLOW 表示属性值列表太小
*/
int of_property_read_u32_index(const struct device_node *np,const char *propname,u32 index, u32 *out_value)

/*
@description:这4个函数分别是读取属性中u8、u16、u32 和 u64类型的数组数据,比如大多数的reg属性都是数组数据,可以使用这 4个函数一次读取出reg属性中的所有数据
@pararm-np:设备节点
@pararm-proname: 要读取的属性名字
@pararm-out_value:读取到的数组值,分别为 u8、u16、u32 和 u64
@pararm-out_sz:要读取的数组元素数量
return:0,读取成功,负值,读取失败,-EINVAL 表示属性不存在,-ENODATA 表示没有要读取的数据,-EOVERFLOW 表示属性值列表太小
*/
int of_property_read_u8_array(const struct device_node *np,const char *propname, u8 *out_values, size_t sz)
int of_property_read_u16_array(const struct device_node *np,const char *propname, u16 *out_values, size_t sz)
int of_property_read_u32_array(const struct device_node *np,const char *propname, u32 *out_values, size_t sz)
int of_property_read_u64_array(const struct device_node *np,const char *propname, u64 *out_values, size_t sz)

其他OF函数

/*
@description:of_iomap 函数本质上也是将 reg 属性中地址信息转换为虚拟地址,如果 reg 属性有多段的话,可以通过 index 参数指定要完成内存映射的是哪一段。
@pararm-np:设备节点
@pararm-index:reg 属性中要完成内存映射的段,如果 reg 属性只有一段的话 index 就设置为 0
return:经过内存映射后的虚拟内存首地址,如果为 NULL 的话表示内存映射失败
*/
void __iomem *of_iomap(struct device_node *np, int index)

设备树在系统中的体现

系统启动以后可以在跟文件系统里面看到设备树的节点信息。在/proc/device-tree/目录下存放着设备树信息;内核启动的时候会解析设备树,然后在/proc/device-tree/目录下呈现出来。

思考

1、设备子节点的属性是从哪儿得来的,谁规定了具体设备的属性?例如ov5640摄像头模块,该模块下面的如此多的属性从哪儿得知需要填入的?

ov5640: ov5640@3c {
		compatible = "ovti,ov5640";//在内核中匹配驱动
		reg = <0x3c>;//IIC设备地址
		pinctrl-names = "default";
		pinctrl-0 = <&pinctrl_csi1>;
		clocks = <&clks IMX6UL_CLK_CSI>;
		clock-names = "csi_mclk";
		pwn-gpios = <&gpio_spi 6 1>;
		rst-gpios = <&gpio_spi 5 0>;
		csi_id = <0>;
		mclk = <24000000>;
		mclk_source = <0>;
		status = "okay";
		port {
			ov5640_ep: endpoint {
				remote-endpoint = <&csi1_ep>;
			};
		};
	};

答:可以通过Linux内核自带的绑定文档中查询(/Documentation/devicetree/bindings),或者向制造商索要参考信息即可。

参考文件

《【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.6》
《领航者ZYNQ之嵌入式Linux开发指南V2.0》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/32261.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【计算机毕业设计】22.毕业设计选题系统ssm源码

一、系统截图&#xff08;需要演示视频可以私聊&#xff09; 引言 近年来&#xff0c;电子商务发展的愈趋成熟使得人们的消费方式以及消费观念发生巨大改变&#xff0c;网上竞拍的拍卖模式随之发展起来。大学拍卖网旨在为湘大学生提供一个线上拍卖的交易平台。平台展示的商品大…

【American English】美式发音,英语发音,美国音音标列表及发音

首先声明&#xff0c;网上各种英式发音和美式发音的教程&#xff0c;而我的目的是寻找美式发音。但是自己现在也是在不断地找寻中&#xff0c;所以资料找错了请莫怪。另外&#xff0c;资料顺序采用部分倒叙&#xff0c;不喜请勿吐槽。 文章目录发音示意图49. [](https://www.bi…

百度地图有感

以前总认为坚持会让我们变强大&#xff0c;但是长大后发现&#xff0c;让我们强大的&#xff0c;是放下。 生活也许就是这样&#xff0c;多一分经验便少一分幻想&#xff0c;以实际的愉快平衡现实的痛苦。 百度地图开放平台 百度地图入门指南 百度地图开发指南 百度地图API文…

性早熟和微生物群:性激素-肠道菌群轴的作用

谷禾健康 肠道菌群 & 性激素 青春期是生命的一个关键阶段&#xff0c;与性成熟相关的生理变化有关&#xff0c;是一个受多种内分泌和遗传控制调控的复杂过程。 青春期发育可以在适当的时候&#xff0c;早熟或延迟。 未经治疗的性早熟的孩子通常不会达到成年身高的全部潜力。…

Activity的最佳实践

文章目录Activity的最佳实践知晓当前是在哪一个Activiy随时随地退出程序启动Activity的最佳写法Activity的最佳实践 知晓当前是在哪一个Activiy 创建一个BaseActivity类,继承AppCompatActivity类.重写onCreate方法 open class BaseActivity : AppCompatActivity() {override…

xilinx PL测 DP 点屏 /接收(二)--RX

环境&#xff1a; a)硬件&#xff1a;官方ZCU106开发板 , tb-fmch-vfmc-dp子卡。 b)软件&#xff1a;vivado2021.1&#xff0c;vitis2021.1&#xff0c;裸机程序。 1、官方例程&#xff1a; 2、DP RX IP &#xff1a; 3、DP RX寄存器&#xff1a; 4、时钟&#xff1a; 5、像素&…

CentOS 6.6系统怎么安装?CentOS Linux系统安装配置图解教程

服务器相关设置如下&#xff1a; 操作系统&#xff1a;CentOS 6.6 64位 IP地址&#xff1a;192.168.21.129 网关&#xff1a;192.168.21.2 DNS&#xff1a;8.8.8.8 8.8.4.4 备注&#xff1a; CentOS 6.6系统镜像有32位和64位两个版本&#xff0c;并且还有专门针对服务器优化过的…

【端到端存储解决方案】Weka,让企业【文件存储】速度飞起来!

一、HK-Weka概述 虹科WekaIO&#xff08;简称HK-Weka&#xff09;是一个可共享、可扩展的文件存储系统解决方案&#xff0c;其并行文件系统WekaFS支持NVMeoF的flash-native并行文件系统、比传统的NAS存储及本地存储更快。 HK-Weka后端主机被配置为集群&#xff0c;它与安装在应…

在Mysql中新建序列Sequence

在Oracle数据库中想要一个连续的自增数据类型的值&#xff0c;可以通过创建一个sequence来实现。而在Mysql数据库中并没有sequence&#xff0c;如想要在Mysql中像Oracle那样使用序列&#xff0c;该如何操作呢&#xff1f;&#xff08;可以使用mysql中的自增主键&#xff09; 1、…

哪个牌子的led灯质量好?2022LED护眼台灯最好的品牌有哪些

谈及led灯的品牌&#xff0c;就不得不提一些比较专业的厂商了&#xff0c;特别是在护眼照明领域&#xff0c;明基、南卡、飞利浦、松下等品牌都有不俗的实力&#xff0c;出产的led护眼台灯在业内都有广泛的知名度&#xff0c;在消费者领域也是好评连连。那么它们到底好在哪儿呢…

蓝牙协议栈分层

一、分层 BLE协议栈主要用来对你的应用数据进行层层封包&#xff0c;以生成一个满足BLE协议的空中数据包&#xff0c;也就是说&#xff0c;把应用数据包裹在一系列的帧头&#xff08;header&#xff09;和帧尾&#xff08;tail&#xff09;中。 BLE协议栈主要由如下几部分组成…

达梦日志分析工具DMLOG使用

达梦日志分析工具DMLOG1.使用工具的目的2.适用范围3.工具描述4.开启跟踪日志记录执行SQL5.使用条件及限制6.使用说明6.1使用前准备6.2使用方法和步骤7.结果解读1.使用工具的目的 分析SQL是DBA或者数据库服务人员很重要的工作。达梦数据库通过开启SVR_LOG捕捉数据库中运行的所有…

SpringBoot+Vue项目实现高校学生健康打卡系统

文末获取源码 开发语言&#xff1a;Java 使用框架&#xff1a;spring boot 前端技术&#xff1a;JavaScript、Vue.js 、css3 开发工具&#xff1a;IDEA/MyEclipse/Eclipse、Visual Studio Code 数据库&#xff1a;MySQL 5.7/8.0 数据库管理工具&#xff1a;phpstudy/Navicat JD…

双通道PID控制器用于热离子发电器中真空度和温度的同时控制

摘要&#xff1a;本文针对真空型热离子能量转换器&#xff08;发电装置&#xff09;中真空压力和温度的关联性复杂控制&#xff0c;提出一个简便的控制方式和控制系统的解决方案&#xff0c;控制系统仅采用一个双通道高精度PID调节器。方案的核心技术思路是将一个可调参量转换为…

接口类型太多了,很多网工总是分不清

交换机光模块的最强科普 以太网交换机常用的光模块有四个&#xff0c;分别是SFP&#xff08;Small Form-factor Pluggabletransceiver&#xff09; 小封装可插拔收发器&#xff0c;GBIC&#xff08;GigaBit Interface Converter&#xff09;千兆以太网接口转换器&#xff0c;X…

往USBKey里面导入双证书专题:概念介绍、执行逻辑

相关概念 国密证书 国密的双证书体系&#xff0c;将证书按照使用目的的不同划分为加密证书和签名证书两种&#xff0c;也就是两对公私钥&#xff0c;二者本质一致&#xff0c;均为SM2密钥对&#xff0c;区别仅体现在用法国密CA体系中&#xff0c;加密密钥对由CA产生&#xff…

力扣刷题记录141.1-----34. 在排序数组中查找元素的第一个和最后一个位置

目录一、题目二、代码三、运行结果一、题目 二、代码 class Solution { public:vector<int> searchRange(vector<int>& nums, int target) {int i,j;int left,right,middle;vector<int> return_vector(2,-1);if(nums.size()<3){for(i0;i<nums.si…

mysql转sqlite3实战+部署sqlite3应用

文章目录场景mysql脚本转sqlite31.新建个sqlite3的文件并使用navicat连接准备好mysql并连接上使用navicat数据传输传输完后&#xff0c;设置主键自增修改应用程序1.添加sqlite3的驱动包2.修改sqlite3的jdbc连接配置文件3.全局替换Date类型字段为String类型4.全局替换 sql文件中…

达摩院WIDER FACE榜首近两年人脸检测MogFace CVPR论文深入解读

一、开源 1.&#xff09;论文链接&#xff1a;https://openaccess.thecvf.com/content/CVPR2022/papers/Liu_MogFace_Towards_a_Deeper_Appreciation_on_Face_Detection_CVPR_2022_paper.pdf 2.&#xff09;代码模型&#xff1a;ModelScope 魔搭社区 3.&#xff09;可玩应用…

新知实验室_初探腾讯云音视频

本文目标&#xff1a; 了解 TRTC 的基本概念 初步运行 demo 调用 API 完成进入视频房间 完成多人进入同一房间 一、腾讯 TRTC 可能有些同学并不知道 RTC 的相关概念&#xff0c; 这里先简单说一下。 WebRTC(web Real-Time Communication) 是指网站实时音视频通话技术。 这项技…