Linux设备树(Linux Device Tree)

这篇具有很好参考价值的文章主要介绍了Linux设备树(Linux Device Tree)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


5.1Linux设备树简介

linux 设备树,Linux驱动开发(i.MX6ULL),linux,驱动开发,c语言

设备树:是一种描述硬件的数据结构,Linux3.x以后的版本才引入了设备树,不是将设备的每个细节都硬编码到操作系统中,而是可以在引导时传递给操作系统的数据结构中描述硬件的许多方面。设备树由OpenFirmware、OpenPOWER抽象层(OPAL)、电源架构平台需求(PAPR)和独立的扁平设备树(FDT)形式使用。
在早些的linux内核,这些“硬件平台的板级细节”保存在linux内核目录“/arch”,
以ARM平台为例“硬件平台的板级细节”保存在“/arch/arm/plat-xxx”和“/arch/arm/mach-xxx”目录下。

5.2设备树和内核的关系

linux 设备树,Linux驱动开发(i.MX6ULL),linux,驱动开发,c语言

设备树是描述一个硬件平台的硬件资源。这个“设备树”可以被bootloader(uboot)传递到内核, 内核可以从设备树中获取硬件信息。在操作系统(OS)引导阶段进行设备初始化(DTB文件在linux内核启动的时候内核解析),解析之后设备树就被放到内存在上(逻辑结构:树状结构)。如果某个驱动需要使用设备信息,直接从设备树上获取对应的设备信息即可。

5.3设备树硬件资源

1、树的主干就是系统的总线,在设备树里称为“根节点”。比如I2C控制器,SPI控制器,CAN控制器等都是接到系统主线上的分支,在设备树上称为“根节点的子节点”
2、设备树可以像头文件(.h)那样,一个设备文件引用另一个设备文件,实现“代码”的重用(复用),例如GEC6818是一款基于ARM公版开发板的产品,它采用了S5P6818芯片作为处理器,如果多个硬件平台都是用S5P6818芯片作为主控芯片,那么我们可以把S5P6818芯片的硬件资源写到一个单独的设备树文件里面一般使用“.dtsi”后缀,其他设备树文件直接使用“#includexxxx”引用即可。

DTS、DTC和DTB它们是文档中常见的几个缩写:

  • DTS 是指.dts格式的文件,是一种ASII 文本格式的设备树描述,也是我们要编写的设备树源码,一般一个.dts文件对应一个硬件平台,位于Linux源码的“/arch/arm/boot/dts”目录下。
  • DTC 是指编译设备树源码的工具,一般情况下我们需要手动安装这个编译工具。
  • DTB 是设备树源码编译生成的文件,类似于我们C语言中“.C”文件编译生成“.bin”文件。
    dtb通过Bootloader引导程序加载到内核。
    linux 设备树,Linux驱动开发(i.MX6ULL),linux,驱动开发,c语言

5.4设备树框架

打开内核源码路径>
linux 设备树,Linux驱动开发(i.MX6ULL),linux,驱动开发,c语言

查看设备树的框架和语法

*设备树根节点*/
/ {
    model = "imx6ull 正点原子";		/*model属性,用于指定设备的制造商和型号*/
        compatible = "fsl,imx6ull-14x14-evk", "fsl,imx6ull";	/*compatible属性,系统用来决定绑定到设备驱动的关键,用来查找节点的方法之一*/

    	/*根节点的子节点*/
        chosen {
                stdout-path = &uart1;
        };
		
    	/*根节点的子节点*/
        memory@80000000 {
                device_type = "memory";
                reg = <0x80000000 0x20000000>;
        };

    	/*根节点的子节点*/
        reserved-memory {
                #address-cells = <1>;
                #size-cells = <1>;
                ranges;
                 linux,cma {
                        compatible = "shared-dma-pool";
                        reusable;
                        size = <0xa000000>;
                        linux,cma-default;
                };
        };
    
    	/*根节点的子节点*/
    	leds {
                compatible = "gpio-leds";
                pinctrl-names = "default";
                pinctrl-0 = <&pinctrl_gpio_leds>;
                status = "okay";

                sysled {
                        lable = "sysled";
                        gpios = <&gpio4 16 GPIO_ACTIVE_HIGH>;
                        linux,default-trigger = "heartbeat";
                        default-state = "off";
                };
           };
      /*-------------以下内容省略-------------*/
};

/*设备树节点追加内容*/
/*+--------------+
  | Misc Modules |
  +--------------+*/
/*而是向原有节点追加内容*/
&uart1 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_uart1>;
        status = "okay";
};

&pwm1 { /* backlight */
        #pwm-cells = <2>;
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_pwm1>;
        status = "okay";
};

设备树里面的每一个“{}”都是一个节点,设备树的源码分为三个部分:

  • 头文件:设备树是可以像C语言那样使用“#include”引用“.h”后缀的头文件,也可以引用设备树“.dtsi”后缀的头文件。imx6ull.dtsi由NXP官方提供,是一个imx6ull平台“共用”的设备树文件。
  • 设备树节点:“/ {…};”表示“根节点”,每一个设备树只有一个根节点。不同文件的根节点最终会合并为一个。在根节点内部的“chosen{…}”、memory{…}”、“reserved-memory{…}”、“leds{…}”等字符,都是根节点的子节点。
  • 设备树节点追加内容:子节点比根节点下的子节点多了一个“&”, 这表示该节点在向已经存在的子节点追加数据。本代码中的“&pwm1{…}”、“&uart1{…}”等等追加的目标节点,就是定义在“imx6ul.dtsi”中。

我们查看imx6ull.dtsi头文件,在内核源码/arch/arm/boot/dts/imx6ull.dtsi

pwm1: pwm@2080000 { /*节点标签:节点名称@单元地址*/
	compatible = "fsl,imx6ul-pwm", "fsl,imx27-pwm";	/*model属性用于指定设备的制造商和型号*/
	reg = <0x02080000 0x4000>;	/*reg属性描述设备资源在其父总线定义的地址空间内的地址*/
	interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;	/*描述中断相关的信息*/
	clocks = <&clks IMX6UL_CLK_PWM1>,	/*初始化GPIO外设时钟信息*/
		     <&clks IMX6UL_CLK_PWM1>;
	clock-names = "ipg", "per";
	#pwm-cells = <3>;		/*表示有多少个cells来描述pwm引脚*/
	status = "disabled";	/*状态属性用于指示设备的“操作状态”*/
};

我们通过文件查看了解到,设备树是由一个根节点和很多个子节点组成的,子节点也可以包含其他节点。

5.5设备树下的节点

5.5.1节点的基本格式

设备树下的节点都有规定的命名格式:

node-name@unit-address{
    属性1 = xx
    属性2 = xx
    属性3 = xx
    子节点xx
}
  • node-name(节点名字):用于表示指定节点的名称,长度为1至31个字符,只能由“数字、大小字母、英文逗号句号、下划线和加减号”组成,节点名应当使用大写或小写字母开头并且能够描述设备类别。
  • @unit-address:其中的符号“@”可以理解为是一个分割符,“unit-address”用于指定“单元地址”, 它的值要和节点“reg”属性的第一个地址一致。如果节点没有“reg”属性值,可以直接省略“@unit-address”。注意同级别的设备树下相同级别的子节点节点名唯一node-name@unit-address 的整体要求同级唯一。
  • 节点标签:节点名的简写,当其它位置需要引用时可以使用节点标签来向该节点中追加内容。在imx6ul.dtsi头文件中,节点名“pwm”前面多了个“pwm1”,这个“pwm1”就是我们所说的节点标签。
  • 节点路径:通过指定从根节点到所需节点的完整路径,可以唯一地标识设备树中的节点,“不同层次的设备树节点名字可以相同,同层次的设备树节点要唯一”。类似于我们Windows上的文件,一个路径唯一标识一个文件或文件夹,不同目录下的文件文件名可以相同。
  • 节点属性:节点的“{}”中包含的内容是节点属性,通常情况下一个节点包含多个属性信息, 这些属性信息就是要传递到内核的“板级硬件描述信息”,驱动中会通过一些API函数获取这些信息。
  • 设备树最主要的内容是编写节点的节点属性,通常情况下一个节点代表一个设备。

5.5.2节点的属性

1.compatible属性
compatible属性值由一个或多个字符串组成,有多个字符串时使用“,”分隔开。

设备树中的每一个设备的节点都要有一个compatible属性。系统通过compatible属性决定绑定哪一个设备的设备驱动,是用来查找节点的方法之一,也可以通过节点名或节点路径查找指定节点。

例如系统初始化时会初始化platform总线上的设备时,根据设备节点”compatible”属性和驱动中of_match_table对应的值加载对应的驱动。

mqs: mqs {              
         compatible = "fsl,imx6sx-mqs";//设置compatible属性值,与mqs平台驱动做匹配
         pinctrl-names = "default";//定义引脚状态
         pinctrl-0 = <&pinctrl_mqs>;//指定mqs引脚的pinctrl信息
         clocks = <&clks IMX6UL_CLK_SAI1>;//设置时钟信号
         clock-names = "mclk";//设置时钟名
         gpr = <&gpr>;//设置寄存器
         status = "okay";//设置mqs操作状态
        };

2.model属性
model属性用于指定设备的制造商和型号。

*设备树根节点*/
/ {
    model = "imx6ull 正点原子";		/*model属性,用于指定设备的制造商和型号*/
			---省略---
}

3.status属性
状态属性用于指示设备的“操作状态”,通过status可以去禁止设备或者启用设备,默认情况下不设置status属性设备是使能的。

mqs:mqs{
			status = "okay";//设置mqs操作状态
		};

4.#address-cells 和 #size-cells

#size-cells和#address-cells决定了子节点的reg属性中哪些数据是“地址”,哪些数据是“长度”信息。
#address-cells,用于指定子节点reg属性“地址字段”所占的字长(单元格cells的个数)。
#size-cells,用于指定子节点reg属性“大小字段”所占的字长(单元格cells的个数)。

例如#address-cells=2,#address-cells=1,每个cells是一个32位宽的数字。

//每个“address length”组合表示一个地址范围,
//其中 address 是起始地址, length 是地址长度,
//#address-cells 表明 address 这个数据所占用的字长,
// #size-cells 表明 length 这个数据所占用的字长.
reg = <address1 length1 address2 length2 address3 length3……>

linux 设备树,Linux驱动开发(i.MX6ULL),linux,驱动开发,c语言

5.reg属性
ret属性的书写格式为reg = < cells cells cells cells cells cells…>

reg属性描述设备资源在其父总线定义的地址空间内的地址。通常情况下用于表示一块寄存器的起始地址(偏移地址)和长度, 在特定情况下也有不同的含义。reg 属性一般用于描述设备地址空间资源信息,一般都是某个外设的寄存器地址范围信息.

例如#address-cells = <1>,#address-cells = <1>,reg = <0x9000000 x4000>, 其中0x9000000表示的是地址,0x4000表示的是地址长度,这里的reg属性指定了起始地址为0x9000000,长度为0x4000的一块地址空间。

6.ranges
该属性提供了子节点地址空间和父地址空间的映射(转换)方法,常见格式是 <子地址、父地址、地址长度>。如果父地址空间和子地址空间相同则无需转换。

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

如果 ranges 属性值为空值,说明子地址空间和父地址空间完全相同,不需要进行地址转换。

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

比如对于#address-cells和#size-cells都为1的话,以ranges=<0x0 0x10 0x20>为例,表示将子地址的从0x0~(0x0 + 0x20)的地址空间映射到父地址的0x10~(0x10 + 0x20)。

7.name和device_type
这两个属性很少用(已经被废弃),不推荐使用。name用于指定节点名,在旧的设备树中它用于确定节点名, 现在我们使用的设备树已经弃用。device_type属性也是一个很少用的属性,只用在CPU和内存的节点上。 如上例中所示,device_type用在了CPU节点。

我们在设备树中添加了一个“led”节点, 正常情况下我们可以从这个节点获取编写led驱动所用到的所有信息,例如led相关控制寄存器地址、 led时钟控制寄存器地址等等。

内核提供了一组函数用于从设备节点获取资源(设备节点中定义的属性)的函数,这些函数以of_开头,称为OF操作函数。文章来源地址https://www.toymoban.com/news/detail-731001.html

到了这里,关于Linux设备树(Linux Device Tree)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 018——红外遥控模块驱动开发(基于HS0038和I.MX6uLL)

    目录 一、 模块介绍 1.1 简介 1.2 协议 二、 驱动代码 三、 应用代码 四、 实验 五、 程序优化         红外遥控被广泛应用于家用电器、工业控制和智能仪器系统中,像我们熟知的有电视机盒子遥控器、空调遥控器。红外遥控器系统分为发送端和接收端,如图下图所示。

    2024年04月16日
    浏览(43)
  • 017——DS18B20驱动开发(基于I.MX6uLL)

    目录 一、 模块介绍 1.1 简介 1.2 主要特点 1.3 存储器介绍 1.4 时序 1.5 命令 1.5.1 命令大全    1.5.2 命令使用 1.5.3 使用示例 1.6 原理图 二、 驱动程序 三、 应用程序 四、 测试         DS18B20 温度传感器具有线路简单、体积小的特点,用来测量温度非常简单,在一根通信线上

    2024年04月12日
    浏览(47)
  • I.MX6ULL_Linux_驱动篇(42)设备树与platform设备驱动

    上一章我们详细的讲解了 Linux 下的驱动分离与分层,以及总线、设备和驱动这样的驱动框架。基于总线、设备和驱动这样的驱动框架, Linux 内核提出来 platform 这个虚拟总线,相应的也有 platform 设备和 platform 驱动。上一章我们讲解了传统的、未采用设备树的 platform 设备和驱

    2024年02月14日
    浏览(42)
  • i.MX6ULL移植NXP官方Linux内核imx_5.4.47_2.2.0

    系统:Ubuntu18.04 参考资料:百问网 IMX6ULL开发板(从零移植篇-预览版)-V0.1,正点原子驱动开发指南 开发板:100ask i.MX6ULL PRO 交叉编译工具链的获取就不写了 打开 .bashrc 文件。 vi ~/.bashrc 。在该文件最后面添加如下(根据自己的交叉编译工具链) (1)直接从官网下载,非常慢而

    2024年02月12日
    浏览(57)
  • 【Linux 裸机篇(五)】I.MX6ULL BSP工程管理下的 Makefile编写、链接脚本

    文件夹 描述 bsp 存放驱动文件 imx6ul 存放跟芯片有关的文件,比如 NXP 官方的 SDK库文件 obj 存放编译生成的.o 文件 project 存放 start.S 和 main.c 文件,也就是应用文件 行 描述 1~7 定义了一些变量,除了第 2 行以外其它的都是跟编译器有关的,如果使用其它编译器的话只需要修改第

    2023年04月20日
    浏览(44)
  • I.MX6ULL开发笔记(二)——硬件外设操作

    在文章http://t.csdnimg.cn/EGWt9中有介绍Linux下文件目录,那么在Linux系统下,RGB灯也是一个设备,所以我们需要到 /sys 目录下去操作这个设备。 之后,我们进入到 class 目录,这里挂载着开发板上的外设: 在这里就能看到熟悉的硬件接口了,那么我们进入到 leds 的目录下: 可以看

    2024年01月24日
    浏览(51)
  • I.MX6ULL_Linux_驱动篇(57)linux Regmap API驱动

    我们在前面学习 I2C 和 SPI 驱动的时候,针对 I2C 和 SPI 设备寄存器的操作都是通过相关的 API 函数进行操作的。这样 Linux 内核中就会充斥着大量的重复、冗余代码,但是这些本质上都是对寄存器的操作,所以为了方便内核开发人员统一访问 I2C/SPI 设备的时候,为此引入了 Reg

    2024年03月26日
    浏览(57)
  • 基于I.MX6ULL的Linux C多线程物联网网关+STM32+Qt上位机+Linux C++多线程服务器(含web)的多种无线通信系统的智慧农场

    我国是农业大国,而非农业强国。近30年来农业高产量主要依靠农药化肥的大量投入,大部分化肥和水资源没有被有效利用而随地弃置,导致大量养分损失并造成环境污染。我国农业生产仍然以传统生产模式为主,传统耕种只能凭经验施肥灌溉,不仅浪费大量的人力物力,也

    2024年04月14日
    浏览(80)
  • 使用一根网线,让Ubuntu和正点原子I.MX6ULL开发板互相ping通

    准备一根网线即可 2.1 找根网线将I.MX6ULL和电脑连起来 2.2 让I.MX6ULL通电运行起来,我这里使用的是正点原子版本的内核、 2.3 进入电脑的网络连接后,按照如下步骤操作 2.4 将ip地址、子网掩码、默认网关设置如下,= 注意,子网掩码一定要是255.255.255.0 IP地址推荐使用192.168.5.

    2024年02月19日
    浏览(48)
  • I.MX6ULL_Linux_驱动篇(45)linux INPUT子系统

    按键、鼠标、键盘、触摸屏等都属于输入(input)设备, Linux 内核为此专门做了一个叫做 input子系统的框架来处理输入事件。输入设备本质上还是字符设备,只是在此基础上套上了 input 框 架,用户只需要负责上报输入事件,比如按键值、坐标等信息, input 核心层负责处理这些

    2024年02月14日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包