【嵌入式Linux】Linux设备树详解

设备树是是Linux中一种用于描述硬件配置的数据结构,它在系统启动时提供给内核,以便内核能够识别和配置硬件资源。设备树在嵌入式Linux系统中尤其重要,因为这些系统通常不具备标准的硬件配置,需要根据实际的硬件配置来动态配置内核。在Linux中,设备树源文件的扩展名为.dts,其二进制编码文件为.dtb,将.dts编译成.dtb需要使用DTC工具,位于Linux内核的scripts/dtc文件夹下

基于 ARM 架构的 SOC 有很多种,一种 SOC 又可以制作出很多款板子,每个板子都有一个对应的 DTS 文件,那么如何确定编译哪一个 DTS 文件呢?我们就以 I.MX6ULL 这款芯片对应的板子为例来看一下,打开 arch/arm/boot/dts/Makefile

// 从381行开始
dtb-$(CONFIG_SOC_IMX6UL) += \
imx6ul-14x14-ddr3-arm2.dtb \
imx6ul-14x14-ddr3-arm2-emmc.dtb \
....
dtb-$(CONFIG_SOC_IMX6ULL) += \
imx6ull-14x14-ddr3-arm2-emmc.dtb \
imx6ull-14x14-ddr3-arm2-flexcan2.dtb \
imx6ull-14x14-ddr3-arm2-gpmi-weim.dtb \
imx6ull-14x14-ddr3-arm2-wm8958.dtb \
imx6ull-14x14-evk.dtb \
imx6ull-14x14-evk-btwifi.dtb \
imx6ull-14x14-evk-emmc.dtb \
imx6ull-14x14-evk-gpmi-weim.dtb \

当选中 I.MX6ULL 这个 SOC 以后(CONFIG_SOC_IMX6ULL=y),所有使用到IMX6ULL 这个 SOC 的板子对应的.dts 文件都会被编译为.dtb。如果使用了这一款SOC搓了一块板子,那么我们只需要新建一个该板子对应的.dts,然后将对应的.dtb文件名添加到dtb-$(CONFIG_SOC_IMX6ULL)下,这样在使用make编译设备树的时候就会将对应的.dts编译为二进制的.dtb

一般dtb文件会和根文件目录以及uboot一同烧录进启动存储设备中。(待补充)

如何编写DTS

虽然我们基本上不会从头到尾重写一个.dts 文件,大多时候是直接在 SOC 厂商提供的.dts文件上进行修改。但是我们肯定需要修改.dts文件,因此DTS 文件语法我们还是要学习一遍

.dtsi头文件

和 C 语言一样,设备树也支持头文件,设备树的头文件扩展名为.dtsi。一般.dtsi 文件用于描述 SOC 的内部外设信息,比如 CPU 架构、主频、外设寄存器地址范围,比如 UART、IIC 等等。设备树是采用树形结构来描述板子上的设备信息的文件,每个设备都是一个节点,叫做设备节点,每个节点都通过一些属性信息来描述节点信息,属性就是键—值对。比如我们使用的正点原子imx6ull使用的设备树是imx6ull-alientek-emmc.dts,而imx6ull-alientek-emmc.dts里又include了imx6ull.dtsi,以下是从imx6ull.dtsi 文件中缩减出来的设备树文件内容:

/ {
	aliases {
		can0 = &flexcan1;
	};

	cpus {
		#address-cells = <1>;
		#size-cells = <0>;

 		cpu0: cpu@0 {
 			compatible = "arm,cortex-a7";
 			device_type = "cpu";
 			reg = <0>;
 		};
 	};

 	intc: interrupt-controller@00a01000 {
 		compatible = "arm,cortex-a7-gic";
 		#interrupt-cells = <3>;
 		interrupt-controller;
 		reg = <0x00a01000 0x1000>,
 			  <0x00a02000 0x100>;
 	};
 }

第 1 行,“/”是根节点,每个设备树文件只有一个根节点。如果有多个dts或dsti,那么这几个设备树文件的根节点会合并为一个根节点。aliases、cpus 和 intc 是三个子节点。

在设备树中节点命名格式为:label:node-name@unit-address,其中“label”是节点标签,主要是方便访问,“node-name”是节点名字,为 ASCII 字符串,“unit-address”一般表示设备的地址或寄存器首地址,如果没有则可以省去,nodename和unit-addr共同构成了节点名字。intc: interrupt-controller@00a01000就是这种命名格式,而label的存在使得使用&cpu0就可以访问cpu@0这个节点

每个节点都有不同属性,不同的属性又有不同的内容,属性都是键值对,值可以为空或任意的字节流。设备树源码中有如下几种数据形式:
1.字符串

compatible = “arm,cortex-a7”;

2.32位无符号整数,可以是一组值也可以是单个值

reg = <0 0x123456 100>;

3.字符串列表,使用‘,’分隔字符串

compatible = “fsl,imx6ull-gpmi-nand”, “fsl, imx6ul-gpmi-nand”;

标准属性

节点是由一堆的属性组成,节点都是具体的设备,不同的设备需要的属性不同,用户可以自定义属性。除了用户自定义属性,有很多属性是标准属性,Linux 下的很多外设驱动都会使用这些标准属性

1. compatible 属性
compatible 属性也叫做“兼容性”属性,compatible 属性的值是一个字符串列表,这个属性的作用是告诉内核,当前的设备节点应该由哪个驱动来处理。内核会根据compatible属性中列出的字符串,去查找与之匹配的驱动程序。如果找到了匹配的驱动,内核就会尝试加载并初始化该驱动,以便操作相应的硬件设备,其格式如下:

compatible = “manufacturer,model”

其中 manufacturer 表示厂商,一般是芯片制造厂商,model 一般是模块对应的驱动名字,比如 imx6ull-alientek-emmc.dts 中 sound 节点是 I.MX6U-ALPHA 开发板的音频设备节点,I.MX6U-ALPHA 开发板上的音频芯片采用的欧胜出品的 WM8960,sound 节点的 compatible 属性值如下:

compatible = “fsl,imx6ul-evk-wm8960”,“fsl,imx-audio-wm8960”;

其中fsl表示厂商是飞思卡尔,“imx6ul-evk-wm8960”是驱动模块的名字,这个属性会遍历字符串列表中符合的驱动程序名称,然后再Linux内核中查找该驱动程序,如果第一个没有则第二个,第二个没有则第三个,直到找到位置。

在内核中,驱动程序通常会提供一个匹配表,这个表中列出了该驱动支持的所有compatible字符串。当内核解析设备树时,它会检查每个设备节点的compatible属性,并与驱动程序的匹配表进行对比,以确定是否应该由该驱动程序来处理该设备节点,比如在文件 imx-wm8960.c 中有如下内容

// 从632行开始
static const struct of_device_id imx_wm8960_dt_ids[] = {
	{ .compatible = "fsl,imx-audio-wm8960", },
	{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, imx_wm8960_dt_ids);

static struct platform_driver imx_wm8960_driver = {
	.driver = {
		.name = "imx-wm8960",
		.pm = &snd_soc_pm_ops,
		.of_match_table = imx_wm8960_dt_ids,
	},
	.probe = imx_wm8960_probe,
	.remove = imx_wm8960_remove,
};

imx_wm8960_dt_idss 就是 imx-wm8960.c 这个驱动文件的匹配表,此匹配表只有一个匹配值“fsl,imx-audio-wm8960”,可以和imx6ull-alientek的dts中sound节点中的compatible 属性的字符串相匹配,那么这个节点就会使用此驱动文件。

2. model属性
model 属性值也是一个字符串,一般 model 属性描述设备模块信息,比如名字什么的,比
如:

model = “wm8960-audio”;

3.status 属性
status 属性看名字就知道是和设备状态有关的,status 属性值也是字符串,字符串是设备的状态信息,可选的状态如表:

描述
“okay”表明设备是可操作的。
“disabled”表明设备当前是不可操作的,但是在未来可以变为可操作的,比如热插拔设备插入以后。至于 disabled 的具体含义还要看设备的绑定文档。
“fail”表明设备不可操作,设备检测到了一系列的错误,而且设备也不大可能变得可操作。
“fail-sss”含义和“fail”相同,后面的 sss 部分是检测到的错误内容

4.#address-cells 和#size-cells 属性
这两个属性的值都是无符号 32 位整形,#address-cells#size-cells 这两个属性可以用在任何拥有子节点的设备中,用于描述子节点的地址信息。#address-cells 属性值决定了子节点 reg 属性中地址信息所占用的字长(32 位),#size-cells 属性值决定了子节点 reg 属性中长度信息所占的字长(32 位)。#address-cells#size-cells 表明了子节点应该如何编写 reg 属性值,一般 reg 属性都是和地址有关的内容,格式如下:

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

每个“address length”组合表示一个子节点设备或其寄存器的地址范围,其中 address 是起始地址,length 是地址长度,addressx表示第x个设备的起始地址,lengthx表示第x个设备的长度,当#address-cells=<1>的时候表示reg中的每一个address的长度是1字长,同样,#size-cells=<1>表示每个length的长度是1字长。

这部分看不懂没关系,后面会有详解

5.reg 属性
reg 属性的值一般是(address,length)对。reg 属性一般用于描述设备地址空间资源信息,一般都是某个外设的寄存器地址范围信息

6.ranges属性
ranges 是一个地址映射/转换表,ranges 属性每个项目由子地址、父地址和地址空间长度
这三部分组成,目的是将:

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

如果 ranges 属性值为空值,说明子地址空间和父地址空间完全相同,不需要进行地址转换。以ranges = <0x0 0xe0000000 0x00100000>;为例,此属性值指定了一个 1024KB(0x00100000)的地址范围子,地址空间的物理起始地址为 0x0,父地址空间的物理起始地址为 0xe0000000,range会将子空间映射到父空间中,这样,我们在写程序的时候就直接以0x0为起点进行编程就好,地址映射会自动映射到父空间的对应位置

特殊属性

chosen属性
aliases属性

设备树的工作方式

在DTS文件中,每个节点都有 compatible 属性,但根节点 compatible 属性值得拿出来单独说一下,通过根节点的 compatible 属性可以知道我们所使用的设备,一般第一个值描述了所使用的硬件设备名字,第二个值描述了设备所使用的 SOC。我们一般会将设备树和uboot一起烧录到启动设备中,uboot在引导Linux内核启动时,会将设备树dtb文件的首地址传给Linux内核,Linux内核检查设备树的根节点compatible 就可以获知当前设备的信息

以IMX6ULL设备为例子,其设备树arch/arm/mach-imx/mach-imx6ul.c的根节点信息如下:

/ {
	model = "Freescale i.MX6 ULL 14x14 EVK Board";
	compatible = "fsl,imx6ull-14x14-evk", "fsl,imx6ull";

Linux内核中存储着其支持的板子和芯片的信息,Linux内核都用MACHINE_STARTMACHINE_END来定义一个machine_desc 结构体来描述这个设备,Linux内核会获取设备树文件dtb的根节点compatible 属性,然后遍历它支持的machine_desc 结构体,用于确认自己是否支持当前设备。该结构体位于arch/arm/include/asm/mach/arch.h,源码如下

#define DT_MACHINE_START(_name, _namestr)		\
static const struct machine_desc __mach_desc_##_name	\
 __used							\
 __attribute__((__section__(".arch.info.init"))) = {	\
	.nr		= ~0,				\
	.name		= _namestr,

#endif

可以看到,要实现该架构体需要两个参数:以IMX6ULL设备为例子,这个设备的machine_desc 结构体实现位于文件 arch/arm/mach-imx/mach-imx6ul.c

static const char *imx6ul_dt_compat[] __initconst = {
	"fsl,imx6ul",
	"fsl,imx6ull",
	NULL,
};

DT_MACHINE_START(IMX6UL, "Freescale i.MX6 Ultralite (Device Tree)")
	.map_io		= imx6ul_map_io,
	.init_irq	= imx6ul_init_irq,
	.init_machine	= imx6ul_init_machine,
	.init_late	= imx6ul_init_late,
	.dt_compat	= imx6ul_dt_compat,
MACHINE_END

machine_desc 结构体中有个.dt_compat 成员变量,此成员变量保存着本设备兼容属性。只要某个设备(板子)根节点“/”的 compatible 属性值与imx6ul_dt_compat 表中的任何一个值相等,那么就表示 Linux 内核支持此设备。而mach-imx6ul.c的根节点的compatible属性中的"fsl,imx6ull"显然与之匹配,那么Linux就可以确认该设备树dtb是自己支持的,从而将设备树加载进来。

Linux内核设备树与machine_desc匹配详解

挖个坑,后面补

如何向设备树中添加新设备

Linux内核的设备树解析过程

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JMeter之mqtt-jmeter 插件介绍

前言 mqtt-jmeter插件是JMeter中的一个第三方插件&#xff0c;用于支持MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;协议的性能测试。MQTT是一种轻量级的发布/订阅消息传输协议&#xff0c;广泛应用于物联网和传感器网络中。 一、安装插件 mqtt-jmeter项目…

Java项目-基于springboot框架的时间管理系统项目实战(附源码+文档)

作者&#xff1a;计算机学长阿伟 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、ElementUI等&#xff0c;“文末源码”。 开发运行环境 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBoot、Vue、Mybaits Plus、ELementUI工具&#xff1a;IDEA/…

数据抓取时,使用动态IP要注意哪些?

在充满竞争和数据驱动的商业环境中&#xff0c;动态IP已成为数据抓取过程中不可或缺的工具。动态IP的应用能有效提高抓取成功率&#xff0c;但同时也伴随着一系列需要注意的问题。在本文中&#xff0c;我们将详细探讨在数据抓取时使用动态IP时应注意的事项&#xff0c;以确保抓…

git-合并连续两次提交(一个功能,备注相同)

前言&#xff1a; 场景是这样&#xff0c;由于我是实现一个功能&#xff0c;先进行了一次commit,然后我发现写的有些小问题&#xff0c;优化了一下功能并且把代码优化了一次&#xff0c;于是又提交了一次。两次的提交都是以相同的备注&#xff08;当然这个无所谓&#xff09;&a…

【设计模式系列】简单工厂模式

一、什么是简单工厂模式 简单工厂模式&#xff08;Simple Factory Pattern&#xff09;是一种设计模式&#xff0c;其中包含一个工厂类&#xff0c;根据传入的参数不同&#xff0c;返回不同类的实例。这个工厂类封装了对象的创建逻辑&#xff0c;使得客户端代码可以从直接创建…

CSDN Markdown 编辑器语法大全

Markdown 是一种轻量级标记语言&#xff0c;它以简洁、易读易写的特点&#xff0c;被广泛应用于技术文档、博客文章、笔记等领域。CSDN 的 Markdown 编辑器为用户提供了丰富的功能&#xff0c;让用户能够轻松地创建格式规范、内容丰富的文档。以下是一份详细的 CSDN Markdown 编…

Python 应用可观测重磅上线:解决 LLM 应用落地的“最后一公里”问题

作者&#xff1a;彦鸿 背景 随着 LLM&#xff08;大语言模型&#xff09;技术的不断成熟和应用场景的不断拓展&#xff0c;越来越多的企业开始将 LLM 技术纳入自己的产品和服务中。LLM 在自然语言处理方面表现出令人印象深刻的能力。然而&#xff0c;其内部机制仍然不明确&am…

本地大模型部署和基于RAG方案的私有知识库搭建

背景与目的 在人工智能领域&#xff0c;大语言模型如GPT系列、BERT等&#xff0c;以其强大的语言生成与理解能力&#xff0c;正在深刻改变着我们的工作与生活方式。这些模型通过海量数据训练而成&#xff0c;能够执行从文本生成、问答系统到代码编写等多种任务。然而&#xff…

目标检测——yolov5-3.1的环境搭建和运行

第一步&#xff1a;安装anaconda环境&#xff0c;并且配置好cuda&#xff0c;安装需要的基本包 查看对应cuda版本&#xff0c;后续下载cudatoolkit需要对应版本 nvcc -V 第二步&#xff1a;创建虚拟环境&#xff0c;激活环境&#xff0c;安装所需的包 conda create -n yolo…

V2X介绍

文章目录 什么是V2XV2X的发展史早期的DSRC后起之秀C-V2XC-V2X 和DSRC 两者的对比 什么是V2X 所谓V2X&#xff0c;与流行的B2B、B2C如出一辙&#xff0c;意为vehicle to everything&#xff0c;即车对外界的信息交换。车联网通过整合全球定位系统&#xff08;GPS&#xff09;导…

一个非常有趣的问题——链表带环问题

目录 前言 一、为什么快指针每次⾛两步&#xff0c;慢指针⾛⼀步可以相遇&#xff0c;有没有可能遇不上 二、快指针⼀次⾛3步&#xff0c;⾛4步&#xff0c;...n步⾏吗? 三、求环形链表中入环的节点 前言 在学习链表的时候我发现一个一个非常有趣的问题链表带环&#xff0c;…

重生之我爱上了k8s!

内容不全&#xff0c;待补充中...... 目录 一、k8s的部署 1.1.集群环境初始化 1.1.1.所有主机禁用swap 1.1.2.安装k8s部署工具 1.1.2.所有节点安装cri-docker 1.1.3.在master节点拉取K8S所需镜像 1.1.4.集群初始化 1.1.5.其他两台主机加入集群 1.1.6.安装flannel网络…

UE4 材质学习笔记12(水体反射和折射)

一.水体反射和折射 首先就是要断开所有连接到根节点的线&#xff0c;因为水有很多不同的节点成分&#xff0c;当所有其他节点都在用时 要分辨出其中一个是何效果是很难的。 虚幻有五种不同的方法可以创建反射&#xff0c;虚幻中的大多数场景使用多种这些方法 它们会同时运作。…

串口头汇总

1 网线头 1 4对应485A &#xff0c; 2 5对应485B &#xff0c;1 4 接在一起&#xff0c;2 5 接在一起转成2根线也可以。 ----------拓展中

简单介绍冯诺依曼体系

现代的计算机, 大多遵守冯诺依曼体系结构 CPU中央处理器&#xff1a;进行算术运算和逻辑判断。存储器&#xff1a;分为外存和内存&#xff0c;用于存储数据&#xff08;使用二进制方式存储&#xff09;。输入设备&#xff1a;用户给计算机发号施令。输出设备&#xff1a;计算机…

【记录】Android|安卓平板 猫游戏(四款,peppy cat,含下载教程和链接)

前言 网上大部分直接找到的都是 iPad 的猫游戏&#xff0c;安卓的要查英文才找得到&#xff0c;但质量也都一般&#xff0c;或不知道在哪里下载。 遂自己找。 下载测试时间&#xff1a;2024/10/20 文章目录 前言1 检索2 亲测2.1 ✅⭐⭐⭐⭐⭐Cat Alone 1 and 22.2 &#x1f4…

Qt中使用线程之moveToThread

步骤&#xff1a; 1、创建一个自定义Worker类&#xff0c;继承自QObject 2、主线程中创建QThread的对象&#xff0c;Worker类的对象 3、Worker类的对象调用moveToThread函数移动到QThread的对象中 4、主线程自定义一个信号&#xff0c;并使用信号槽连接到worker类对象的任务…

身份和访问管理平台(IAM)是数字身份管理的关键路径和重要方法

随着数字化转型不断推进&#xff0c;越来越多的企业选择通过身份和访问管理平台&#xff08;IAM&#xff09;来管理数字身份。IAM不只是传统的账号、认证、授权、审计产品&#xff0c;更是数字身份管理的创新领航者&#xff0c;以权威数字身份为基础&#xff0c;结合用户与数字…

Python爬取京东商品信息,详细讲解,手把手教学(附源码)

Python 爬虫爬取京东商品信息 下面我将逐一解释每一部分的代码 导入库 from selenium import webdriver from selenium.webdriver.edge.service import Service from selenium.webdriver.edge.options import Options import time import random import csv from selenium.c…

VMware中Ubuntu安装

VMware官网&#xff1a;https://www.vmware.com/products/desktop-hypervisor/workstation-and-fusion 先在官网下载VMware&#xff0c;一直根据默认点下一步就好了&#xff0c;记得更改安装地址哦&#xff0c;否则默认下在C盘里。 先下载好Ubuntu映像文件&#xff1a;https://…