众所周知操作系统一直在不断的更新和发展,而在Linux驱动的架构上面也是不断的进步和完善。在早期的Linux内核和ARM架构中并没有采用设备树。在没有设备树的时候Linux是通过大量的arch/arm/mach-xxx 和arch/arm/plat-xxx文件夹来描述对应平台的板机信息。而随着智能终端设备,智能手机的发展,每年新出的ARM架构芯片都有数百款,从而导致Linux内核中的板机信息文件过多,使得Linux内核虚胖
       当 Linux之父 linus看到 ARM社区向 社区向 Linux内核添加了大量“无用”、冗余的板级信息文件,不禁发出了一句“ This whole ARM thing is a f*cking pain in the ass”。从此以后 ARM社区就引入了PowerPC等架构已经采用的设备树(Flattened Device Tree),将这些描述板机硬件信息的内容都从Linux中分离出来,用一个专属的文件格式来描述,这个专属的文件就叫做设备树。 这个用这个通用的文件就是.dtsi文件,类似于C语言中的头文件。一般用.dts描述板机信息(也就是开发板上有多少个IIC设备、SPI设备等),dtsi描述SOC级信息(也就是SOC有几个CPU、主频是多少、多少个外设控制寄存器信息等)
往期推荐:
       从单片机到ARM Linux驱动——Linux驱动入门
       Linux字符设备驱动开发(2)——让开发板上的LED灯闪烁

文章目录

  • 什么是设备树
  • DTS、DTB和DTC
    • DTS语法
      • .dtsi头文件
      • 设备节点
      • 标准属性
    • 根节点 compatible属性

什么是设备树

设备树(Device Tree),将这个词分开就是“设备”和“树”,描述设备设备树的文件叫做DTS(Device Tree Source),这个DTS文件采用了树形结构来描述板机设备,也就是开发板信息,比如CPU数量、内存基地址、IIC接口上接了那些设备、SPI接口上接了那些设备等。如最开始的图片所示!
       在图片中,树的主干就是系统总线,IIC控制器、SPI控制器等都是接到系统主线的分支上的。通过DTS这个文件描述设备信息是有相关的语法规则的,并且在Linux内核中只有3.x版本以后的才支持设备树。

DTS、DTB和DTC

设备树源文件扩展名为.dts, 之前我跟着正点原子的教程时一直使用的是.dtb文件,这两个文件的关系是什么呢?其实DTS是设备树源码文件DTB是将DTS编译以后得到的一个二进制文件。在Linux中将.c文件编译成.o文件需要用到gcc编译器,那么将 ** .dts编译为.dtb需要用到的工具就是DTC工具**!而这个.dtb文件就是UBOOT通过bootz或者bootm命令向Linux内核中传递的二进制设备树文件(.dtb))。

DTS语法

虽然在平时工作中我们基本上不会从头到尾写一个.dts文件,但是我作为学生来学习这么一个知识可以尝试着学习一下.dts的基本语法,同时也为以后找工作可能修改SOC原厂提供的.dts文件上进行修改。DTS其实是一种ASCII文本文件,不论是阅读还是修改都相对比较方便。

.dtsi头文件

和C语言一样,设备树也支持头文件,设备树的头文件扩展名为.dtsi。在imx6ull-alientek-emmc.dts中有以下内容:

12 #include <dt-bindings/input/input.h> //引用了“input.h”这个.h头文件
13 #include "imx6ull.dtsi" //引用.dtsi头文件

通过以上代码可以看出在.dtsi文件中可以直接通过include来引用.h.dtsi.dts。一般的.dtsi用于描述SOC的内部外设信息,比如CPU架构、主频、外设寄存器地址范围,比如UART、IIC等等。

设备节点

设备树采用树形结构来描述板子上的设备信息的文件,每一个设备都是一个节点,叫做设备节点,每个节点都是通过一些属性信息来描述节点信息,属性就是键值对。以下是借鉴正点原子驱动开发手册的从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>; };
}
  • /是根节点,每个设备树文件只有一个根节点,如果工程中有两个或者多个文件都有一个/根节点,那么这些文件中的根节点的内容会合并成一个根节点。
  • aliases、cpus和intc是三个子节点,在设备树中节点命名格式为node-name@unit-address
    • node-name是节点的名字,为ASCII字符串,节点名字应该能够清晰的辨别出节点的功能,比如uart1就表示这个节点是UART1外设。unit-address一般表示设备的地址或寄存器首地址,如果某个节点没有地址或者寄存器的话unit-address可以不要,比如cpu@0interrupt-controller@00a01000
    • cpu0:cpu@0并不是node-name@unit-address这样的格式,而是用隔开成了两部分,前面是节点标签,后面是节点名字,格式为lable:node-name@unit-address,引入label的目的就是为了方便访问节点,可以直接通过&label来访问这个节点,比如通过&cpu0就可以访问cpu@0这个节点,而不需要输入完整的节点名字。
  • 上述代码中的cpu0也是一个节点,只是cpu0是cpus的子节点。每个节点都有不同的属性,不同的属性又有不同的内容,属性都是键值对,值可以为空或任意的字节流。
           设备树中常用的几种数据形式如下所示:
数据形式 实现方式 详细描述
字符串 compatible = "arm,cortex-a7; 设置compatible属性的值为字符串arm,cortex-a7
32位无符号整数 reg=<0> 设置reg的值也可以设置为一组值reg=<0 0x123456 100>;
字符串列表 compatible = "fsl,imx6ull-gpmi-nand", "fsl, imx6ul-gpmi-nand"; 字符串与字符串之间用隔开

标准属性

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

  1. compatible属性

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

"manufacturer,model"

其中的manufacturer表示厂商,model一般是模块对应驱动的名字。I.MX6U-ALPHA开发板上的音频芯片采用的欧圣出品的WM8960,sound节点的compatible属性如下:

compatible = "fsl,imx6ul-evk-wm8960","fsl,imx-audio-wm8960";

可以看出属性值有两个,分别是"fsl,imx6ul-evk-wm8960"和"fsl,imx-audio-wm8960",其中的fsl表示厂商是飞思卡尔,imx6ul-evk-wm8960imx-audio-wm8960表示驱动模块的名字。sound这个设备首先使用第一个兼容值再Linux内核中查找,查看能否找到对应的驱动文件,如果没有找到的话就使用第二个兼容值查找,直到找到或者查找玩整个Linux内核也没有找到对应的驱动。
        一般程序驱动程序文件都会有一个OF匹配表,此OF匹配表保存着一些compatible值,如果设备节点的compatible属性值和OF匹配表中的任何一个值相等,那么就表示设备可以使用这个驱动

  1. model属性
            model属性值也就是一个字符串,一般model属性描述设备模块信息,比如名字什么的,比如:
model=”wm8960-audio";
  1. status属性
           status属性看名字就知道是和设备状态有关的,status属性值也是字符串,字符串是设备的状态信息,可以选择的状态如表所示:
描述
okay 表明设备是可操作的
disabled 表明设备当前是不可操作的,但是在未来可以变为可操作的,比如热插拔设备插入以后。至于disabled的具体含义还要看设备绑定文档
fail 表明设备不可操作,设备检测到了一系列的错误,而且设备也大可能变得可操作
fail-sss 含义和fail相同,后面的sss部分是检测到的错误内容
  1. #address-cells和#size-cells属性
           这两个属性都是无符号32位整型,#address-cells和#size-cells这两个属性可以用在任何拥有子节点的设备中,用于描述子节点的地址信息。#address-cells属性决定了子节点reg属性中地址信息所占用的字长(32位), #size-cells属性值决定了子节点应该如何编写reg属性值,一般reg属性都是和地址有关的内容,和地址相关的信息有两种:起始地址和地址长度,reg属性的格式为:reg = <address1 length1 address2 length2 address3 length3…… >
           每个address length组合表示一个地址范围,其中address是起始地址,length是地址长度,#address-cells表明address这个数据所占用的字长,#size-cells表明length这个数据所占用的字长,比如:
spi4 { compatible = "spi-gpio"; #address-cells = <1>; #说明了spi4的子节点reg属性中起始地址所占用的字长为1#size-cells = <0>; #地址长度所占用的字长为0gpio_spi: gpio_spi@0 { #reg属性值为0,因为父节点中设置了相关的值,继承父节点起始地址,没有设置地址长度compatible = "fairchild,74hc595"; reg = <0>; }; };
aips3: aips-bus@02200000 { compatible = "fsl,aips-bus", "simple-bus"; #address-cells = <1>; #size-cells = <1>; dcp: dcp@02280000 { compatible = "fsl,imx6sl-dcp"; reg = <0x02280000 0x4000>; #address=0X02280000,length=0X4000};
};
  1. reg属性
           reg属性值一般是(address,length)。一般用于描述设备地址空间资源信息,一般都是某个外设的寄存器地址范围信息

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

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

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

  1. name属性
           name属性值为字符串,name属性用于记录节点名字,name属性已经被弃用,不推荐使用name属性,一些老的设备树文件可能会使用此属性。
  2. device_type属性
           device_type属性值为字符串,IEEE1275会用到此属性,用于描述设备的Fcode,但是设备树没有FCode,所以此属性也被抛弃了。此属性只能用于cpu节点或者memory节点。imx6ull.dtsi的CPU0节点用到了此属性,内容如下所示:
cpu0: cpu@0 { compatible = "arm,cortex-a7"; device_type = "cpu"; reg = <0>; ......
};

根节点 compatible属性

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

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

可以看出根节点的compatible属性可以知道我们所使用的设备,一般第一个值描述了所使用的硬件设备名字,使用某个设备第二个值就是描述设个设备所使用的SOC,如果使用的是imx6ull这颗SOC。Linux内核会通过根节点的compoatible属性查看是否支持此设备,如果支持这个设备的话设备就会启动Linux内核。

未使用设备树的设备匹配方法

在没有使用设备树之前,uboot会向Linux内核传递一个叫machine id的值,machine id也就是设备ID,告诉Linux内核自己是一个什么设备,看看Linux内核是否支持。具体实现就是判断machine id这个参数是否与代码中的宏MACH_TYPE_XXX进行对比,看有没有相等的,如果相等的话就表示Linux内核支持这个设备,如果不支持的话那么这个设备就没法启动Linux内核。

使用设备树的设备匹配方法

当Linux内核引入设备树以后就不在使用MACHINE_START了,而是换为了DT_MACHINE_START。说明引入了设备树以后就不会根据machine id来检查Linux 内核是否支持这个设备。在Linux内核中通过start_kernel函数启动内核,然后start_kernel函数会调用setup_arch函数来匹配machine_desc,然后再调用setup_machine_fdt函数进一步获取匹配的machine_desc,这个函数的参数就是atags的首地址(也就是uboot传递给Linux内核的dtb文件首地址),setup_machine_fdt函数返回值就是找到的最匹配的machine_desc。然后通过of_get_flat_dt_root获取设备树的根节点。

不积小流无以成江河,不积跬步无以至千里。而我想要成为万里羊,就必须坚持学习来获取更多知识,用知识来改变命运,用博客见证成长,用行动证明我在努力。
       如果我的博客对你有帮助、如果你喜欢我的博客内容,记得“点赞” “评论” “收藏”一键三连哦!听说点赞的人运气不会太差,每一天都会元气满满呦!如果实在要白嫖的话,那祝你开心每一天,欢迎常来我博客看看。

Linux设备树是什么?相关推荐

  1. Linux设备树语法详解【转】

    转自:http://www.cnblogs.com/xiaojiang1025/p/6131381.html 概念 Linux内核从3.x开始引入设备树的概念,用于实现驱动代码与设备信息相分离.在设备 ...

  2. Linux设备树相关函数

    Linux设备树相关函数 Linux内核提供了一系列函数来获取设备树中的节点和属性信息. 查找节点:of_find_node_by_name() 函数通过节点名字查找指定的节点of_find_node ...

  3. Linux设备树OF API 中OF的含义

    * 前言 读Linux内核源码或者开源GPL程序源码时,看到各种英文首字母缩写满天飞,英文单词首字母缩写是Unix/Linux C 编程的一个历史习惯,部分英文首字母缩写结合上下文可以找到理解含义,但 ...

  4. Linux 设备树的使用技巧

    Linux内核从3.x开始引入设备树的概念,用于实现驱动代码与设备信息相分离.在设备树出现以前,所有关于设备的具体信息都要写在驱动里,一旦外围设备变化,驱动代码就要重写.引入了设备树之后,驱动代码只负 ...

  5. Linux设备树特殊节点(aliases、chosen)介绍

    引用一个特定的节点通常使用全路径,aliases 节点可以用于指定一个设备全路径的别名.例如: 1 2 3 4 aliases {         ethernet0 = ð0;         se ...

  6. 【正点原子MP157连载】第二十三章 Linux设备树-摘自【正点原子】STM32MP1嵌入式Linux驱动开发指南V1.7

    1)实验平台:正点原子STM32MP157开发板 2)购买链接:https://item.taobao.com/item.htm?&id=629270721801 3)全套实验源码+手册+视频 ...

  7. linux 设备树详解

    2 Linux 设备树 2.1 什么是设备树? 设备树(Device Tree),将这个词分开就是"设备"和"树",描述设备树的文件叫做DTS(Device T ...

  8. Linux设备树led,linux设备树下LED灯控制

    linux设备树下LED灯控制 linux设备树下LED灯控制 原理图: 所以在设备树下子节点下插入gpioled节点: gpioled { #address-cells = <1>; # ...

  9. 正点原子----Linux设备树详解

    linux设备树 1.什么是设备树 2.DTS.DTB.DTC的关系 3.如何编译设备树 4.DTS基本结构 4.1.语法 4.2.设备树在系统中的体现 4.3.尝试自己添加节点 4.4.尝试对根节点 ...

  10. 【正点原子Linux连载】第四十三章 Linux设备树 -摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0

    1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址: ...

最新文章

  1. Java项目:医院预约挂号系统(java+SpringBoot+Maven+Vue+mysql)
  2. 中国安全态势越来越好,专访山石网科CSO蒋东毅 | 拟合
  3. simulink和psim仿真结果不同_案例展示金属增材制造过程仿真分析 (下篇)- 微观尺度...
  4. 美国银行将 AI 应用于企业应收账款处理;联合国或将利用机器学习技术帮助救灾工作...
  5. easyui placeholder 解决方案
  6. 我如何使用React,Redux-Saga和Styled Components构建NBA球员资料获取器
  7. csv导入mysql_京东金融数据分析:MySQL+HIVE的结合应用案例详解【附全代码】
  8. XML学习笔记--导航
  9. 5G怎样实现波束赋形?
  10. python读图片生成ROI并保存
  11. python多PDF文件合成一个
  12. 将World中的向下箭头替换为回车符
  13. c语言中排列组合函数,排列组合c怎么算公式是什么
  14. 外贸找客户软件:Email Extractor Pro
  15. 计算机硬件的组装实践,论文-计算机硬件组装实践.doc
  16. 加密币Terra创始人权道亨已从新加坡飞往杜拜转往第三国
  17. MBA关注:创始人CEO该拿多少工资?
  18. Build file: no target in no project
  19. saf java_Android SAF实现外置SD卡的写入JAVA层与JNI层hook
  20. 【论文阅读】Federated Learning应用扩展合集

热门文章

  1. CREO5.0二次开发+VS2019配置详解
  2. 币圈里,大佬们都在用的网站和APP都在这
  3. Android 10.0 行为变更(一)针对所有 API 级别的应用
  4. 高级会计师英语计算机考试,高级会计师考试是否需要考职称英语和计算机
  5. 自动驾驶 9-1: (线性)卡尔曼滤波器The (Linear) Kalman Filter
  6. win11什么时候发布的_2021专升本考试政策什么时候发布
  7. 阿里国际站新出的优品抢位会是弯道超车的新机会吗?
  8. Spring AOP 切入点表达式
  9. 小程序 多张图片上传(源码分享+实现分析)
  10. 解决thingsboard 二开 跨域问题