设备树简介

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

1 设备树

简单的整理记录;
学习参考内容:

  • Linux 笔记 https://xuesong.blog.csdn.net/article/details/109522945?spm=1001.2014.3001.5502
  • 正点原子-左盟主 驱动开发
  • 网络资料:IT界小生 https://www.zhihu.com/column/itlife

1.1 设备树简介

设备树是一种描述硬件的数据结构,它起源于OpenFirmware(OF)。
在Linux 2.6中, ARM架构的板极硬件细节过多地被硬编码在arch/arm/plat-xxx和arch/arm/mach-xxx中,采用设备树后,许多硬件的细节可以直接通过它传递给Linux,而不再需要在内核中进行大量的冗余编码。

1.2 DTS、DTB、DTC

DTS:
1.dts文件是设备树的源文件。
2 由于一个SoC可能对应多个设备,这些.dst文件可能包含很多共同的部分,共同的部分一般被提炼为一个.dtsi文件,这个文件相当于C语言的头文件。
3 可针对单独设备编写对应dts文件,调用.dtsi;
DTC:
DTC是将.dts编译为.dtb的工具,相当于gcc。
DTB:
.dtb文件是 .dts 被 DTC 编译后的二进制格式的设备树文件,它可以被linux内核解析。

make dtbs

2 DTS语法

2.1 .dts.dtsi

和 C 语言一样,设备树也支持头文件,设备树的头文件扩展名为 .dtsi;同时也可以像C 语言一样包含 .h头文件;
例如:(imx6ull-alientek-emmc.dtsi)

#include <dt-bindings/input/input.h>
#include "imx6ull.dtsi"

注:.dtsi 文件一般用于描述 SOC 的内部外设信息,比如 CPU 架构、主频、外设寄存器地址范围,比如 UART、 IIC 等等。

2.2 设备节点及属性

设备树简介
在设备树中节点命名格式如下:

node-name@unit-address

node-name:是设备节点的名称,为ASCII字符串,节点名字应该能够清晰的描述出节点的功能,比如“uart1”就表示这个节点是UART1外设;unit-address:一般表示设备的地址或寄存器首地址,如果某个节点没有地址或者寄存器的话 “unit-address” 可以不要;

注:根节点没有node-name 或者 unit-address,它被定义为 /。

2.3节点属性

设备树中的每个节点都有描述节点特征的属性。属性由名称和值组成

2.3.1节点属性

compatible 属性

compatible 属性也叫做 “兼容性” 属性,这是非常重要的一个属性!compatible 属性的值是一个字符串列表, compatible 属性用于将设备和驱动绑定起来。字符串列表用于选择设备所要使用的驱动程序。compatible 属性值的推荐格式:

 "manufacturer,model"

① manufacturer : 表示厂商;
② model : 一般是模块对应的驱动名字。

注:一般驱动程序文件都会有一个 OF 匹配表,此 OF 匹配表保存着一些 compatible 值,如果设备节点的 compatible
属性值和 OF 匹配表中的任何一个值相等,那么就表示设备可以使用这个驱动。可通过了解驱动模型获取该知识点

model 属性

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

model = "Samsung S3C2416 SoC";
phandle 属性

phandle属性为devicetree中唯一的节点指定一个数字标识符,节点中的phandle属性,它的取值必须是唯一的(不要跟其他的phandle值一样),例如:

pic@10000000 {
phandle = <1>;
interrupt-controller;
};
another-device-node {
interrupt-parent = <1>; // 使用phandle值为1来引用上述节点
};

注:DTS中的大多数设备树将不包含显式的phandle属性,当DTS被编译成二进制DTB格式时,DTC工具会自动插入phandle属性。

label属性
label:node-name@unit-address

PIC: pic@10000000 {
interrupt-controller;
};

another-device-node {
interrupt-parent = <&PIC>; // 使用label来引用上述节点,
// 使用lable时实际上也是使用phandle来引用,
// 在编译dts文件为dtb文件时, 编译器dtc会在dtb中插入phandle属性
};

status 属性

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

status值 描述
#address-cells 和 #size-cells

#address-cells 和 #size-cells的值都是无符号 32 位整型,可以用在任何拥有子节点的设备中,用于描述子节点的地址信息。
#address-cells 属性值决定了子节点 reg 属性中地址信息
#size-cells 属性值决定了子节点 reg 属性中长度信息
#address-cells 和 #size-cells 表明了子节点应该如何编写 reg 属性值,一般 reg 属性都是和地址有关的内容,和地址相关的信息有两种:起始地址和地址长度,reg 属性的格式一为:

reg = <address1 length1 address2 length2 address3 length3……>
soc {
    #address-cells = <2>;
    #size-cells = <1>;
    serial {
        compatible = "xxx";
        reg = <0x4600 0x5000 0x100>;  /*地址信息是:0x00004600 00005000,长度信息是:0x100*/
        };
};
reg 属性

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

例如:一个设备有两个寄存器块,一个的地址是0x3000,占据32字节;另一个的地址是0xFE00,占据256字节,表示如下:

reg = <0x3000 0x20 0xFE00 0x100>;

注:上述对应#address-cells = <1>; #size-cells = <1>;。

ranges 属性

ranges属性值可以为空或者按照 (child-bus-address,parent-bus-address,length) 格式编写的数字矩阵, ranges 是一个地址映射/转换表, ranges 属性每个项目由子地址、父地址和地址空间长度这三部分组成:

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

soc {
    compatible = "simple-bus";
    #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>;
        };
};

节点 soc 定义的 ranges 属性,值为 <0x0 0xe0000000 0x00100000>,此属性值指定了一个 1024KB(0x00100000) 的地址范围,子地址空间的物理起始地址为 0x0,父地址空间的物理起始地址为 0xe0000000。

serial 是串口设备节点,

reg 属性定义了 serial 设备寄存器的起始地址为 0x4600,寄存器长度为 0x100。

经过地址转换, serial 设备可以从 0xe0004600 开始进行读写操作,0xe0004600=0x4600+0xe0000000。

name 属性

name 属性值为字符串, name 属性用于记录节点名字, name 属性已经被弃用,不推荐使用name 属性,一些老的设备树文件可能会使用此属性。

device_type 属性

device_type 属性值为字符串, IEEE 1275 会用到此属性,用于描述设备的 FCode,但是设备树没有 FCode,所以此属性也被抛弃了。此属性只能用于 cpu 节点或者 memory 节点。

memory@30000000 {
    device_type = "memory";
    reg =  <0x30000000 0x4000000>;
};

2.3.2 节点

根节点

每个节点都有 compatible 属性,根节点“/”也不例外,imx6ull-alientek-emmc.dts 文件中根
节点的 compatible 属性内容如下所示:

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

compatible 有两个值:“fsl,imx6ull-14x14-evk”和“fsl,imx6ull”。设备节点的 compatible 属性值是为了匹配 Linux 内核中的驱动程序,那么根节点中的 compatible属性是为了做什么工作的? 通过根节点的 compatible 属性可以知道我们所使用的设备,一般第一个值描述了所使用的硬件设备名字,比如这里使用的是“imx6ull-14x14-evk”这个设备,第二个值描述了设备所使用的 SOC,比如这里使用的是“imx6ull”这颗 SOC。Linux 内核会通过根节点的compoatible 属性查看是否支持此设备,如果支持的话设备就会启动 Linux 内核;

/aliases 子节点

aliases 节点的主要功能就是定义别名,定义别名的目的就是为了方便访问节点。

例如:定义 flexcan1 和 flexcan2 的别名是 can0 和 can1。

aliases {
can0 = &flexcan1;
can1 = &flexcan2;
};

/memory 子节点

所有设备树都需要一个memory设备节点,它描述了系统的物理内存布局。如果系统有多个内存块,可以创建多个memory节点,或者可以在单个memory节点的reg属性中指定这些地址范围和内存空间大小。

例如:一个64位的系统有两块内存空间:RAM1:起始地址是0x0,地址空间是 0x80000000;RAM2:起始地址是0x10000000,地址空间也是0x80000000;同时根节点下的 #address-cells = <2>和#size-cells = <2>,这个memory节点描述为:

memory@0 {
    device_type = "memory";
    reg = <0x00000000 0x00000000 0x00000000 0x80000000
           0x00000000 0x10000000 0x00000000 0x80000000>;
};

或者:

memory@0 {
    device_type = "memory";
    reg = <0x00000000 0x00000000 0x00000000 0x80000000>;
};
memory@10000000 {
    device_type = "memory";
    reg = <0x00000000 0x10000000 0x00000000 0x80000000>;
};
/chosen 子节点

chosen 并不是一个真实的设备, chosen 节点主要是为了 uboot 向 Linux 内核传递数据,重点是 bootargs 参数。例如:

chosen {
    bootargs = "root=/dev/nfs rw nfsroot=192.168.1.1 console=ttyS0,115200";
};
/cpus 和 /cpus/cpu* 子节点

cpus节点下有1个或多个cpu子节点, cpu子节点中用reg属性用来标明自己是哪一个cpu,所以 /cpus 中有以下2个属性:
#address-cells // 在它的子节点的reg属性中, 使用多少个u32整数来描述地址(address)
#size-cells // 在它的子节点的reg属性中, 使用多少个u32整数来描述大小(size) 必须设置为0
例如:

cpus {
    #address-cells = <1>;
    #size-cells = <0>;
    cpu@0 {
        device_type = "cpu";
        reg = <0>;
        cache-unified;
        cache-size = <0x8000>; // L1, 32KB
        cache-block-size = <32>;
        timebase-frequency = <82500000>; // 82.5 MHz
        next-level-cache = <&L2_0>; // phandle to L2
        L2_0:l2-cache {
            compatible = "cache";
            cache-unified;
            cache-size = <0x40000>; // 256 KB
            cache-sets = <1024>;
            cache-block-size = <32>;
            cache-level = <2>;
            next-level-cache = <&L3>; // phandle to L3
            L3:l3-cache {
                compatible = "cache";
                cache-unified;
                cache-size = <0x40000>; // 256 KB
                cache-sets = <0x400>; // 1024
                cache-block-size = <32>;
                cache-level = <3>;
                };
            };
        };
    cpu@1 {
        device_type = "cpu";
        reg = <1>;
        cache-unified;
        cache-block-size = <32>;
        cache-size = <0x8000>; // L1, 32KB
        timebase-frequency = <82500000>; // 82.5 MHzclock-frequency = <825000000>; // 825 MHz
        cache-level = <2>;
        next-level-cache = <&L2_1>; // phandle to L2
        L2_1:l2-cache {
            compatible = "cache";
            cache-unified;
            cache-size = <0x40000>; // 256 KB
            cache-sets = <0x400>; // 1024
            cache-line-size = <32>; // 32 bytes
            next-level-cache = <&L3>; // phandle to L3
            };
        };
};

2.3.3 修改节点内容

原则上不要去修改.dtsi上的内容,这个是共用的文件;建议以追加的形式去修改板子对应dts文件
比如.dtsi部分内容如下

i2c1: i2c@021a0000 {
	#address-cells = <1>;
 	#size-cells = <0>;
 	compatible = "fsl,imx6ul-i2c", "fsl,imx21-i2c";
 	reg = <0x021a0000 0x4000>;
 	interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
 	clocks = <&clks IMX6UL_CLK_I2C1>;
 	status = "disabled";
};

比如.dts部分内容如下

&i2c1 {
 	 clock-frequency = <100000>;
 	 pinctrl-names = "default";
 	 pinctrl-0 = <&pinctrl_i2c1>;
 	 status = "okay";
/* 要追加或修改的内容 */
 	 fxls8471@1e {
 	 compatible = "fsl,fxls8471";
 	 reg = <0x1e>;
 	 position = <0>;
 	 interrupt-parent = <&gpio5>;
 	 interrupts = <0 8>;
 };

3 DTB文件分析

.dtb文件是 .dts 被 DTC 编译后的二进制格式的设备树文件;这块不是不重要,是在深度方面和本文不符,Linux源码跟读,写的有一篇比较详细的,可参阅;
https://zhuanlan.zhihu.com/p/141623370

4 设备树binding文档

设备树是用来描述板子上的设备信息的,不同的设备其信息不同,反映到设备树中就是属性不同。那么我们在设备树中添加一个硬件对应的节点的时候从哪里查阅相关的说明呢?在Linux 内核源码中有详细的.txt 文档描述了如何添加节点,这些.txt 文档叫做绑定文档,路径为:
Linux 源码目录/Documentation/devicetree/bindings

比如我们现在要想在 I.MX6ULL 这颗 SOC 的 I2C 下添加一个节点,那么就可以查看Documentation/devicetree/bindings/i2c/i2c-imx.txt,此文档详细的描述了 I.MX 系列的 SOC 如何在设备树中添加 I2C 设备节点

5 其它

设备树在系统中的体现

Linux 内核启动的时候会解析设备树中各个节点的信息,并且在根文件系统的/proc/device-tree 目录下根据节点名字创建不同文件夹
设备树简介

# 设备树常用 OF 操作函数
设备树描述了设备的详细信息,这些信息包括数字类型的、字符串类型的、数组类型的,
我们在编写驱动的时候需要获取到这些信息。比如设备树使用 reg 属性描述了某个外设的寄存
器地址为 0X02005482,长度为 0X400,我们在编写驱动的时候需要获取到 reg 属性的0X02005482 和 0X400 这两个值,然后初始化外设。Linux 内核给我们提供了一系列的函数来获
取设备树中的节点或者属性信息,这一系列的函数都有一个统一的前缀“of_”,所以在很多资料里面也被叫做 OF 函数。这些 OF 函数原型都定义在 include/linux/of.h 文件中。文章来源地址https://www.toymoban.com/news/detail-437448.html

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

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

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

相关文章

  • Spring Cloud学习笔记:Eureka简介,Eureka简单样例

    这是本人学习的总结,主要学习资料如下 - 马士兵教育 Eureka 是 SpringCloud Nexflix 的核心子模块,其中包含 Server 和 Client 。 Server 提供服务注册,存储所有可用服务节点。 Client 用于简化和 Server 的通讯复杂度。 下面是 Eureka 的简单架构图 每一个服务节点需要在 Eureka Server 中注册

    2024年04月16日
    浏览(55)
  • 小白的学习记录——Redis的简单使用

    Redis是什么? 不同于MySql,MySql是基于二维表存储数据, 而Redis是一个基于内存的key-value键值对结构数据库 我们为什么要用Redis? 基于内存存储,读写性很高 适合存储热点数据,(热点商品,资讯,新闻) 企业应用广泛 Redis是对MySql的补充,与其共存,大部分数据放在MySql中。

    2024年03月09日
    浏览(31)
  • STM32入门教程课程简介(B站江科大自化协学习记录)

    STM32最小系统板+面包板硬件平台 STM32面包板入门套件 Windows电脑 万用表、示波器、镊子、剪刀等 Keil MDK 5.24.1 是一款嵌入式软件开发工具,它提供了一个完整的开发环境,包括编译器、调试器和仿真器。它支持各种微控制器,包括 ARM、Cortex-M、Cortex-R 和 8051 等。Keil MDK 是一款

    2023年04月08日
    浏览(72)
  • [FPGA 学习记录] 简单组合逻辑——多路选择器

    封面来源:Multiplexer 在本小节中,我们将使用 Verilog 语言描述一个具有多路选择器功能的电路,目的是学会使用 Verilog 语言实现简单的组合逻辑 本小节的主要内容分为两个部分:一个部分是理论学习,在这一部分我们会对本小节涉及到的理论知识做一个讲解;另一个部分是实

    2024年02月03日
    浏览(35)
  • github 最简单的使用步骤(个人学习记录~)

    github 使用步骤: (11条消息) github新手用法详解(建议收藏!!!)_github详解_怪 咖@的博客-CSDN博客 1.获取ssh密钥 打开输入:ssh-keygen -t rsa -C “git账号” 输入之后一路Enter(确认)就可以了 2.绑定ssh 将整个id_rsa.pub内容复制进去 Git bash上边输入: 来检查是否成功绑定。如果输

    2024年02月16日
    浏览(45)
  • Fast Planner——代码解读参考资料整理

    参数解读 主要函数解读 概率栅格地图,概率更新过程的公式推导过程 全概率公式、贝叶斯公式 一. kinodynamic a_star(前端hybrid A_star动力学路径搜索) 1.1启发函数的计算 1.2 Compute shot Traj 1.3 节点扩张 1.4 节点剪枝 1.5 返回kinopath与 getsamples 二、B样条曲线设置 2.1 均匀B样条设置

    2024年02月05日
    浏览(93)
  • 学习记录09:快速上手简单改进yolov5目标检测网络

      这篇博客主要是简单介绍一下如何改进yolov5,但是不会讲得太深,因为我也只是运用了几个月,并没有细读每一段代码,我只是为了改而改,不会深究他的代码逻辑,python代码他确实写的很优雅,但是我不打算学习这种优雅,能毕业就行,以后又不从事python工作,也不继

    2023年04月21日
    浏览(53)
  • 【设备树笔记整理7】实践操作

    1.1 修改方法         根据设备节点的compatible属性,在驱动程序中构造/注册 platform_driver,在 platform_driver 的 probe 函数中获得中断资源。 1.2 实验方法 以下是修改好的代码:第6课第1节_网卡_触摸屏驱动\\001th_dm9000dm9dev9000c.c 第6课第1节_网卡_触摸屏驱动\\002th_touchscreens3c_ts.c

    2024年02月09日
    浏览(25)
  • Django学习记录:初步认识django以及实现了简单的网页登录页面的前后端开发

    1、可以先删去template文件夹,并在setting里面删掉这一行 2、在pycharm中创建app: 3、启动app:编写URL与视图函数关系【urls.py】 ​ 编写视图函数【views.py】 ​ 启动pycharm项目 4、引用静态文件 其中有两个文件的导入:(jquery和bootstrap) jquery:https://code.jquery.com/jquery-3.6.0.min.js 可

    2024年02月14日
    浏览(47)
  • 【学习记录】使用高德地图API开发一个简单基础的WebGIS系统(GIS考研院校专题地图网站)

    本人只是一个普普通通的 GIS 学生, 下面是记录我的写的一个作业 demo 的内容, 可能会存在一定的错误, 欢迎在评论区私信交流! *完整功能展示看这里 (B站) *感兴趣可以下载完整 demo 看看 (阿里云盘) 本网站(GIS考研院校可视化专题网站)为2022年GIS考研初期准备择校的学生服务

    2024年02月13日
    浏览(85)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包