设备树

  • 一、设备树概念
  • 二、DTS、DTB和DTC
  • 三、DTS语法
    • 3.1 .dtsi头文件
    • 3.2 设备节点
      • 3.2.1 字符串
      • 3.2.2 32 位无符号整数
      • 3.2.3 字符串列表
    • 3.3 标准属性
      • 3.3.1 compatible 属性
      • 3.3.2 model 属性
      • 3.3.3 status 属性
      • 3.3.4 #address-cells 和#size-cells 属性
      • 3.3.5 reg 属性
      • 3.3.6 ranges 属性
      • 3.3.7 name 属性
      • 3.3.8 device_type 属性
    • 3.4 根节点 compatible 属性
      • 3.4.1 使用设备树之前的设备匹配方法
      • 3.4.1 使用设备树之后的设备匹配方法
    • 3.5 向节点追加或修改内容
  • 四、设备树demo
  • 五、设备树在系统中的体现
  • 六、设备树特殊节点
    • aliases子节点
    • chosen子节点
  • 七、内核解析DTB文件
  • 八、绑定信息文档.txt
  • 九、设备树常用OF操作函数
    • 9.1 查找节点的OF函数
    • 9.2 查找父/子节点的OF函数
    • 9.3 提取属性值的OF函数
    • 9.4 其他常用的OF函数

一、设备树概念

  设备树被用来描述板级信息,包括:CPU的数量和类别、内存基地址和大小、总线和桥、外设链接、中断控制器和中端使用情况、GPIP控制器和GPIO使用情况、Clock控制器和Clock使用情况等。
  设备树信息被保存在一个ASCII文本文件中,适合人类的阅读习惯,类似于xml文件,在ARM Linux中,一个.dts文件对应一个ARM的machine,放置在内核的arch/arm(arm64)/boot/dts中。
  设备树是一种数据结构用于描述设备信息的语言,具体而言,是用于操作系统中描述硬件,使得不需要对设备的信息进行硬编码(hard code)。
  设备树由一系列被命名的**节点(node)属性(property)**组成,而节点本身可包含子节点。所谓属性,其实就是成对出现的键值对(key-value)。
  设备树源文件dts被编译成dtb二进制文件,在bootloader运行时传递给操作系统,操作系统对其进行展开(Flattened),从而产生一个硬件设备的拓扑图,有这个拓扑图,在编码的过程中就可以直接通过系统提供的接口获取到设备树的节点和属性信息。

二、DTS、DTB和DTC

  .dts文件通过DTC工具编译为.dtb,可以理解为.c文件通过GCC工具编译为.o文件。

待补充:
  DTC工具源码及其Makefile;
  加载及编译设备树文件;

三、DTS语法

  目的是会写一个小型设备树,设备树详细语法规则请参考《》

3.1 .dtsi头文件

在.dts文件中使用“#include”来引用“imx6ull.dtsi”这个.dtsi 头文件。

//示例代码 43.3.1.1 imx6ull-alientek-emmc.dts 文件代码段
#include "imx6ull.dtsi"

一般.dtsi 文件用于描述 SOC 的内部外设信息,比如 CPU 架构、主频、外设寄存器地址范
围,比如 UART、IIC 等等。比如 imx6ull.dtsi 就是描述 I.MX6ULL 这颗 SOC 内部外设情况信息
的。

/** 参考源码为imx6ul.dtsi,在 imx6ul.dtsi 文件中不仅仅描述了cpu0 这一个节点信息,* 还将I.MX6ULL 这颗SOC的外设都描述了,比如ecspi1~4、uart1~8、usbphy1~2和i2c1~4等等。*// {#address-cell = <1>;#size-cell = <1>;chosen {};aliases {ethernet0 = &fec1;   //别名};cpus {address-cell = <1>;address-cell = <0>;cpu0: cpu@0 {...};};...soc {#address-cells = <1>;#size-cells = <1>;compatible = "simple-bus";interrupt-parent = <&gpc>;ranges;ocram: sram@900000 {};...dma_apbh: dma-apbh@1804000 {};aips1: aips-bus@2000000 {compatible = "fsl,aips-bus", "simple-bus";#address-cells = <1>;#size-cells = <1>;reg = <0x02000000 0x100000>;ranges;spba-bus@2000000 {compatible = "fsl,spba-bus", "simple-bus";#address-cells = <1>;#size-cells = <1>;reg = <0x02000000 0x40000>;ranges;ecspi1: ecspi@2008000 {};ecspi2: ecspi@200c000 {};ecspi3: ecspi@2010000 {};};pwm1: pwm@2080000 {};pwm2: pwm@2084000 {};};aips2: aips-bus@2100000 {compatible = "fsl,aips-bus", "simple-bus";#address-cells = <1>;#size-cells = <1>;reg = <0x02100000 0x100000>;ranges;adc1: adc@2198000 {};i2c1: i2c@21a0000 {};i2c2: i2c@21a4000 {};uart5: serial@21f4000 {compatible = "fsl,imx6ul-uart","fsl,imx6q-uart";reg = <0x021f4000 0x4000>;interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;clocks = <&clks IMX6UL_CLK_UART5_IPG>,<&clks IMX6UL_CLK_UART5_SERIAL>;clock-names = "ipg", "per";status = "disabled";};};};
};

3.2 设备节点

设备树是采用树形结构来描述板子上的设备信息的文件,每个设备都是一个节点,叫做设
备节点,每个节点都通过一些属性信息来描述节点信息,属性就是键值对。

/ {aliases {can0 = &flexcan1;};cpus {#address-cells = <1>;#size-cells = <0>;cpu0: cpu@0 {compatilble = "arm,cortex-a7";device_type = "cpu";};};intc: interrupt-controller@00a01000 {/** 设备就是节点,叫做设备节点* 有属性就意味着是设备节点,设备节点便是具体设备是吗?* 可以理解为有键值对就是具体设备吗?* 在dtsi中应该不是,因为是头文件的共性信息,具体设备应该是在dts文件中* dtsi中应该是设备节点及其信息。*/compatilble = "arm,cortex-a7-gic";#interrupt-cells = <3>;interrupt-controller;reg = <0x00a01000 0x1000>,<0x00a02000 0x1000>;};
};

aliases、cpus 和 intc 是三个子节点,在设备树中节点命名格式如下:node-name@unit-address
其中“node-name”是节点名字,为 ASCII 字符串。“unit-address”一般表示设备的地址或寄
存器首地址,如“interrupt-controller@00a01000”。

label: node-name@unit-address
intc: interrupt-controller@00a01000
引入 label 的目的就是为了方便访问节点,可以直接通过&label 来访问这个节点,比如通过
&cpu0 就可以访问“cpu@0”这个节点。

3.2.1 字符串

compatible = "arm,cortex-a7";

上述代码设置 compatible 属性的值为字符串“arm,cortex-a7”。

3.2.2 32 位无符号整数

reg = <0>;

上述代码设置 reg 属性的值为 0,reg 的值也可以设置为一组值,比如:

reg = <0 0x123456 100>;

3.2.3 字符串列表

属性值也可以为字符串列表,字符串和字符串之间采用“,”隔开,如下所示:

compatible = "fsl,imx6ull-gpmi-nand", "fsl, imx6ul-gpmi-nand";

上述代码设置属性 compatible 的值为“fsl,imx6ull-gpmi-nand”和“fsl, imx6ul-gpmi-nand”。

3.3 标准属性

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

3.3.1 compatible 属性

compatible 属性用于将设备和驱动绑定起来。一般驱动程序文件都会有一个 OF 匹配表,此 OF 匹配表保存着一些 compatible 值,如果设备节点的 compatible 属性值和 OF 匹配表中的任何一个值相等,那么就表示设备可以使用这个驱动。

待补充:
内核函数和compatible属性的逻辑调用关系;

3.3.2 model 属性

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

3.3.3 status 属性

status属性描述设备状态信息。

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

3.3.4 #address-cells 和#size-cells 属性

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

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

每个“address length”组合表示一个地址范围,其中 address 是起始地址,length 是地址长度,#address-cells 表明 address 这个数据所占用的字长,#size-cells 表明 length 这个数据所占用
的字长。
用以下代码举个实例说明:

aips3: aips-bus@02200000 {compatible = "fsl,aips-bus", "simple-bus";#adress-cells = <1>;    //节点起始地址 长度所占字节为1#size-cells = <0>;      //地址 长度所占字节为1dcp: dcp@02280000 {compatible = "fsl,imx6sl-dcp";//adress = 0x02280000,length = 0x4000//相当于起始地址为0x02280000,地址长度为0x4000reg = <0x02280000 0x4000>;};
};

3.3.5 reg 属性

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

3.3.6 ranges 属性

3.3.7 name 属性

3.3.8 device_type 属性

3.4 根节点 compatible 属性

Linux 内核会通过根节点的 compoatible 属性查看是否支持此设备,如果支持的话设备就会启动 Linux 内核。

3.4.1 使用设备树之前的设备匹配方法

3.4.1 使用设备树之后的设备匹配方法

对这个流程没有自己追一追的话,始终差点感觉。

待补充:
追代码流程;

3.5 向节点追加或修改内容

硬件修改了,我们就要同步的修改设备树文件。
在开发板的.dts文件中进行数据追加:比如在i2c1 节点追加一个名为 fxls8471 的子节点

//访问i2c1这个label对应的节点,也即i2c1@021a0000
&i2c1 {clock-frequency = <100000>; //表示时钟为100KHZpinctrl-names = "default";pinctrl-0 = <&pinctrl_i2c1>;status = "okay";    //status 属性的值由原来的 disabled 改为 okay//NXP官方开发板在I2C1上接了一个磁力计芯片mag3110mag3110@0e {compatible = "fsl,mag3110";reg = <0x0e>;position = <2>;};//NXP官方开发板在I2C1上接了六轴芯片fxls8471fxls8471@le {compatible = "fsl,fxls8471";reg = <0x1e>;position = <0>;interrupt-parent = <&gpio5>;interrupts = <0 8>;};
};

四、设备树demo

五、设备树在系统中的体现

六、设备树特殊节点

aliases子节点

aliases 节点的主要功能就是定义别名,定义别名的目的就是为了方便访问节点。不过我们一般会在节点命名的时候会加上 label,然后通过&label来访问节点,这样也很方便,而且设备树里面大量的使用&label 的形式来访问节点。

aliases {ethernet0 = &fec1;ethernet1 = &fec2;gpio0 = &gpio1;gpio1 = &gpio2;gpio2 = &gpio3;gpio3 = &gpio4;gpio4 = &gpio5;i2c0 = &i2c1;i2c1 = &i2c2;i2c2 = &i2c3;i2c3 = &i2c4;mmc0 = &usdhc1;mmc1 = &usdhc2;serial0 = &uart1;serial1 = &uart2;serial2 = &uart3;serial3 = &uart4;serial4 = &uart5;serial5 = &uart6;serial6 = &uart7;serial7 = &uart8;sai1 = &sai1;sai2 = &sai2;sai3 = &sai3;spi0 = &ecspi1;spi1 = &ecspi2;spi2 = &ecspi3;spi3 = &ecspi4;usbphy0 = &usbphy1;usbphy1 = &usbphy2;};

chosen子节点

chosen 节点主要是为了 uboot 向 Linux 内核传递数据,重点是 bootargs 参数。一般.dts 文件中 chosen 节点通常为空或者内容很少。

chosen函数调用流程:

七、内核解析DTB文件

在 start_kernel 函数中完成了设备树节点解析的工作,最终实际工作的函数为 unflatten_dt_node。

八、绑定信息文档.txt

Linux 内核源码中有详细的.txt 文档描述了如何添加节点,这些.txt 文档叫做绑定文档,路径为:Linux 源码目录/Documentation/devicetree/bindings。
比如我们现在要想在 I.MX6ULL 这颗 SOC 的 I2C 下添加一个节点,那么就可以查看Documentation/devicetree/bindings/i2c/i2c-imx.txt,此文档详细的描述了 I.MX 系列的 SOC 如何在设备树中添加 I2C 设备节点。文档内容如下所示:

* Freescale Inter IC (I2C) and High Speed Inter IC (HS-I2C) for i.MXRequired properties:
- compatible :- "fsl,imx1-i2c" for I2C compatible with the one integrated on i.MX1 SoC- "fsl,imx21-i2c" for I2C compatible with the one integrated on i.MX21 SoC- "fsl,vf610-i2c" for I2C compatible with the one integrated on Vybrid vf610 SoC
- reg : Should contain I2C/HS-I2C registers location and length
- interrupts : Should contain I2C/HS-I2C interrupt
- clocks : Should contain the I2C/HS-I2C clock specifierOptional properties:
- clock-frequency : Constains desired I2C/HS-I2C bus clock frequency in Hz.The absence of the property indicates the default frequency 100 kHz.
- dmas: A list of two dma specifiers, one for each entry in dma-names.
- dma-names: should contain "tx" and "rx".
- scl-gpios: specify the gpio related to SCL pin
- sda-gpios: specify the gpio related to SDA pin
- pinctrl: add extra pinctrl to configure i2c pins to gpio function for i2cbus recovery, call it "gpio" stateExamples:i2c@83fc4000 { /* I2C2 on i.MX51 */compatible = "fsl,imx51-i2c", "fsl,imx21-i2c";reg = <0x83fc4000 0x4000>;interrupts = <63>;
};i2c@70038000 { /* HS-I2C on i.MX51 */compatible = "fsl,imx51-i2c", "fsl,imx21-i2c";reg = <0x70038000 0x4000>;interrupts = <64>;clock-frequency = <400000>;
};i2c0: i2c@40066000 { /* i2c0 on vf610 */compatible = "fsl,vf610-i2c";reg = <0x40066000 0x1000>;interrupts =<0 71 0x04>;dmas = <&edma0 0 50>,<&edma0 0 51>;dma-names = "rx","tx";pinctrl-names = "default", "gpio";pinctrl-0 = <&pinctrl_i2c1>;pinctrl-1 = <&pinctrl_i2c1_gpio>;scl-gpios = <&gpio5 26 GPIO_ACTIVE_HIGH>;sda-gpios = <&gpio5 27 GPIO_ACTIVE_HIGH>;
};

有时候使用的一些芯片在 Documentation/devicetree/bindings 目录下找不到对应的文档,这个时候就要咨询芯片的提供商,让他们给你提供参考的设备树文件。

九、设备树常用OF操作函数

待补充:
各具体定义及其使用;

9.1 查找节点的OF函数

设备都是以节点的形式“挂”到设备树上的,因此要想获取这个设备的其他属性信息,必须先获取到这个设备的节点。Linux 内核使用 device_node 结构体来描述一个节点,此结构体定义在文件 include/linux/of.h 中,定义如下:

struct device_node {const char *name;    //节点名字const char *type; //设备类型phandle phandle;const char *full_name;    //节点全名struct fwnode_handle fwnode;struct    property *properties;   //属性struct  property *deadprops;    /* removed properties */struct  device_node *parent;    //父节点struct device_node *child;     //子节点struct device_node *sibling;
#if defined(CONFIG_OF_KOBJ)struct   kobject kobj;
#endifunsigned long _flags;void *data;
#if defined(CONFIG_SPARC)const char *path_component_name;unsigned int unique_id;struct of_irq_controller *irq_trans;
#endif
};

9.2 查找父/子节点的OF函数

9.3 提取属性值的OF函数

9.4 其他常用的OF函数

参考文章:
https://blog.csdn.net/qq_35031421/article/details/105002645#comments_16910375

Linux驱动开发-设备树-正点原子相关推荐

  1. STM32MP157驱动开发——设备树下的LED驱动

    STM32MP157驱动开发--设备树下的LED驱动 主要内容:将之前章节中使用新设备设备驱动编写的LED驱动改成设备树形式 文章目录 STM32MP157驱动开发--设备树下的LED驱动 一.主要步 ...

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

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

  3. I.MX6ULL ARM驱动开发---设备树下的platfrom设备驱动

    引言   最新的 Linux 内核已经支持了设备树,因此在设备树下如何编写 platform 驱动就显得尤为重要,本章我们就来学习一下如何在设备树下编写 platform 驱动. 一.设备树下的 pl ...

  4. Linux 设备驱动开发 —— 设备树在platform设备驱动中的使用

    关与设备树的概念,我们在Exynos4412 内核移植(六)-- 设备树解析 里面已经学习过,下面看一下设备树在设备驱动开发中起到的作用 Device Tree是一种描述硬件的数据结构,设备树源(De ...

  5. linux 驱动之设备树基础概念

    Table of Contents 一.设备节点 1.1.节点命名方式 1.2.aliases 节点 1.3.memory节点 1.4.chosen 节点 二.节点内的属性 1.属性值格式 2.1.1 ...

  6. I.MX6ULL ARM驱动开发---设备树下的LED驱动实验

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

  7. Linux驱动_设备树下LED驱动

    前言 学习完设备树基础知识后,完成设备树下LED驱动实验 一.修改设备树文件 在设备书根/节点下添加子节点led信息: alphaled {status = "okay";comp ...

  8. Linux驱动之设备树

    14.设备树 1.什么是设备树? ​ 设备树是一种描述硬件资源的数据结构, 它通过bootloader将硬件资源传给内核,使得内核和硬件资源描述相对独立. 2.设备树的由来 要想了解为什么会有设备树, ...

  9. linux 驱动 到 设备树,tree - Linux:设备树到acpi驱动程序 - 堆栈内存溢出

    我需要帮助,我的驱动程序已经在设备树模式下工作,并且我想为其支持acpi模式,但我仍然无法创建分区: 设备树: &spi0 { status = "ok"; flash: ...

最新文章

  1. Pycharm中一些不为人知的技巧pycharm技巧
  2. java算法例子_java算法小例子
  3. MySQL索引(B+Tree 索引、哈希索引、全文索引、 空间数据索引)、索引优化、优点、使用场景
  4. php-fpm通过request_slowlog_timeout检查哪个脚本执行时间长
  5. 排序千万级数据_从千万级房产成交量排名,窥探中国城市的真实家底
  6. python3字符串常用操作
  7. 5怎么用修改器_经常用电脑辐射大怎么办?这5个习惯防辐射,很多人都知道
  8. 微信隐藏功能系列2:微信语音怎么转发?
  9. usbserver专业解决用友u8和t3USB加密狗虚拟化识别解决方案
  10. 桌面美化 Python tkinter倒计时工具
  11. 2008中国优秀无线互联网站点50强
  12. 基于springboot老年人健康体检系统(带论文)
  13. 冒泡排序,快速排序,归并排序,插入排序,希尔排序,堆排序,计数排序,桶排序,基数排序...
  14. DNS不能解析外网与正确设置DNS的技术分享
  15. 数据结构常见问题系列(二)
  16. 简要描述临界资源、临界区及互斥同步机制的原则
  17. 微信公众号支付开发步骤Java(超详细)
  18. 金蝶EAS服务器安装局部补丁时,提示无法安装
  19. python学习笔记(类)
  20. 推荐8个Github上能赚钱的小程序源码

热门文章

  1. Mac 终端命令大全能
  2. 【从零单排HBase 01】从一无所知到5分钟快速了解HBase
  3. 准备笔记 -- 虚函数
  4. 美国公派出国做访问学者可以带家属吗?
  5. Exchange 2013/2016监控邮箱的一些介绍
  6. 在nodejs中创建child process
  7. 郭怀北计算机一级excel,计算机一级考试选择题题库之excel题及答案(最新版)(16页)-原创力文档...
  8. Python17个常用内置模块总结 (运维)
  9. 安全技术系列之Java一句话木马
  10. 软考系统分析师倒计时第1天