[X]关闭

关于设备树

文档创建者:东吴
浏览次数:438
最后更新:2024-09-02

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

6、设备树结构如下:
image.jpg

二、设备树常用语
  在设备树(Device Tree)的语境中,有一些常见的术语和概念。以下是一些常见的设备树用语:
1、Device Tree (DT):设备树本身,是一种数据结构和语言,用于描述硬件资源信息。
2、Device Tree Source (DTS):设备树源代码文件,使用特定的语法格式描述片上片外的设备信息,可以理解为C语言的.c文件。
3、Device Tree Source Include (DTSI):更通用的设备树代码,一般包含在DTS文件中,用于提供共用的设备描述,可以理解为可以理解为C语言的.h文件。
4、Device Tree Blob (DTB):DTS编译后得到的二进制文件,由BootLoader传递给kernel进行解析,可以理解为c语言的.hex或者bin文件。
5、Device Tree Compiler (DTC):设备树编译器,用于将DTS文件编译成DTB文件。这个工具类似于gcc,用于编译C语言源代码(可以理解为keli工具)。
6、硬件资源信息:设备树描述的信息包括CPU的数量和类别、内存基地址和大小、总线和桥、外设连接、中断控制器和中断使用情况、GPIO控制器和GPIO使用情况、Clock控制器和Clock使用情况等。
7、节点(Node):在设备树中用来描述硬件设备或资源的一个独立部分。每个节点都有一个唯一的路径和一组属性。
8、属性(Property):用于描述节点的特征和配置信息,包括设备的名称、地址、中断号、寄存器配置等。
9、属性值(Property Value):属性中的具体数据,可以是整数、字符串、布尔值等各种类型。
10、父节点和子节点(Parent Node and Child Node):在设备树中,每个节点都可以有一个父节点和多个子节点,用于描述设备之间的连接关系。


三、设备树的文件结构
  我们通常使用.dts(设备树源文件)或.dtsi(设备树源文件包含文件)来写设备树。编写完成以后通过DTC工具编译生成 .dtb(设备树二进制)文件,内核在启动时加载这个二进制文件来获得必要的硬件信息。DTS、DTSI、DTC、DTB之间的关系如下图:
image.jpg
  归类下来常用的文件为以下四类:DTS、DTSI、DTB和Makefile。它们各有不同的作用,并且之间存在一定的关系。
1、DTS文件是设备树的源文件,以".dts"为后缀。它使用一种特定的语法,用于描述硬件设备及其相关信息,比如设备名称、类型、地址、中断等。DTS文件是人可读的文本文件,可以被处理器编译成DTB文件,它相当于C语言中的.c文件。
2、DTSI文件是设备树源文件的包含文件,以".dtsi"为后缀。它用于存储一些常用的设备树片段,这些片段可以在多个DTS文件中重复使用,避免了代码重复。DTSI文件可以在DTS文件中进行包含(类似C语言的#include),以便重用其中定义的设备树片段。
3、DTB文件是设备树的二进制文件,以".dtb"为后缀。它是通过将DTS文件编译而来的,使用了特定的编译器工具,比如dtc(Device Tree Compiler)。DTB文件是机器可读的二进制格式,可以被操作系统加载和解析,以用于设备驱动的配置和初始化。它相当于C语言中的.bin文件。
4、Makefile:Makefile是一个用于构建和编译项目的脚本文件。在设备树的上下文中,Makefile用于自动化编译和构建DTS/DTSI文件,生成对应的DTB文件。


四、设备树框架
设备树用树状结构描述设备信息,它有以下几种特性:
1、每个设备树文件都有一个根节点,每个设备都是一个节点。
2、节点间可以嵌套,形成父子关系,这样就可以方便的描述设备间的关系。
3、每个设备的属性都用一组key-value对(键值对)来描述。
4、每个属性的描述用;结束

  所以,一个设备树的基本框架可以写成下面这个样子,一般来说,/表示板子,它的子节点node1表示SoC上的某个控制器,控制器中的子节点node2表示挂接在这个控制器上的设备(们)。
/{                                  //根节点
    node1{                          //node1是节点名,是/的子节点
        key=value;                  //node1的属性
        ...
        node2{                      //node2是node1的子节点
            key=value;              //node2的属性
            ...
        }
    }                               //node1的描述到此为止
    node3{
        key=value;
        ...
    }
}


五、KEY
  在设备树中,键值对是描述属性的方式,比如,Linux驱动中可以通过设备节点中的"compatible"这个属性查找设备节点。
  Linux设备树语法中定义了一些具有规范意义的属性,包括:compatible, address, interrupt等,这些信息能够在内核初始化找到节点的时候,自动解析生成相应的设备信息。此外,还有一些Linux内核定义好的,一类设备通用的有默认意义的属性,这些属性一般不能被内核自动解析生成相应的设备信息,但是内核已经编写的相应的解析提取函数,常见的有 "mac_addr","gpio","clock","power"。"regulator" 等等。


六、设备树属性
1、compatible
compatible 属性值为字符串列表,⽤于将设备和驱动绑定起来,字符串列表⽤于选择设备所要使用的驱动程序
"manufacturer,model"     //anufacturer :厂商  model:模块对应的驱动名
一般驱动程序文件中都会有一个 OF 匹配表,此 OF 匹配表保存着一些 compatible 值,如果设备节点的 compatible 属性值和 OF 匹配表中的任何一个值相等,那么就表示设备可以使用这个驱动。
2、model 属性
model 属性:描述设备模块信息,比如名字什么的,如:model = “wm8960-audio”。
3、status 属性
status 属性:描述设备状态,如:okay - 设备可操作,disabled - 设备不可操作
4、#address-cells 和 #size-cells 属性
#address-cells 用来描述子节点"reg"属性的地址表中用来描述首地址的cell的数量。
#size-cells 用来描述子节点"reg"属性的地址表中用来描述地址长度的cell的数量。
#address-cells = <1>表示address字段的长度为1
#size-cells = <1>; 表示length字段的长度为1
5、ranges 属性
ranges它是一个地址映射/转换表,如果 ranges 属性值为空值,说明子地址空间和父地址空间完全相同,不需要进行地址转换。
6、reg属性
reg的组织形式为reg = <address1 length1 [address2 length2] [address3 length3] ... >其中的每一组adddress length 表明了设备使用的一个地址范围。
7、aliases 节点
用 aliases 节点给多个同类型的控制器分配唯一编号,便于Linux内核区分。在Linux启动时会解析aliases节点。
8、chosen 节点
chosen 并不是一个真实的设备,主要用于将 uboot 中的 bootargs 环境变量值传递给 Linux 内核作为命令行参数。
9、gpio
gpio也是最常见的IO口,常用的属性有"gpio-controller",用来说明该节点描述的是一个gpio控制器。
"#gpio-cells",用来描述gpio使用节点的属性一个cell的内容,即 `属性 = <&引用GPIO节点别名 GPIO标号 工作模式>。
10、interrupts
一个计算机系统中大量设备都是通过中断请求CPU服务的,所以设备节点中就需要在指定中断号。常用的属性有
(1)interrupt-controller 一个空属性用来声明这个node接收中断信号,即这个node是一个中断控制器。
(2)#interrupt-cells,是中断控制器节点的属性,用来标识这个控制器需要几个单位做中断描述符,用来描述子节点中"interrupts"属性使用了父节点中的interrupts属性的具体的哪个值。一般,如果父节点的该属性的值是3,则子节点的interrupts一个cell的三个32bits整数值分别为:<中断域 中断 触发方式>,如果父节点的该属性是2,则是<中断 触发方式>
(3)interrupt-parent,标识此设备节点属于哪一个中断控制器,如果没有设置这个属性,会自动依附父节点的
(4)interrupts,一个中断标识符列表,表示每一个中断输出信号

七、实例
    / {  
        compatible = "acme,coyotes-revenge"; //表示该设备与特定硬件或平台兼容。
        #address-cells = <1>;  
        #size-cells = <1>;  
        //分别设置地址和大小单元为 1,用于描述后续子节点中地址和大小的格式。
        interrupt-parent = <&intc>; //指向根节点下的中断控制器,<&intc> 是一个对中断控制器节点的引用。  
      
        cpus {  
            #address-cells = <1>;  
            #size-cells = <0>;  
            cpu@0 {  
                compatible = "arm,cortex-a9";  
                reg = <0>;  
            };  
            cpu@1 {  
                compatible = "arm,cortex-a9";  
                reg = <1>;  
            };  
        };//描述 CPU 配置,指定了两个 ARM Cortex-A9 处理器。每个 CPU 节点通过 compatible 和 reg 属性定义。reg 属性指定了 CPU 的唯一标识符。

      
        serial@101f0000 {  
            compatible = "arm,pl011";  
            reg = <0x101f0000 0x1000 >;  
            interrupts = < 1 0 >;  
        };  
      
        serial@101f2000 {  
            compatible = "arm,pl011";  
            reg = <0x101f2000 0x1000 >;  
            interrupts = < 2 0 >;  
        }; //有两个串行接口,它们的地址、大小以及中断都有具体说明。
           //compatible: "arm,pl011" 表示这些串行接口与 ARM PL011 兼容。
           //reg: 指定了设备的基地址和映射的内存区域大小。
           //interrupts: 指定了设备使用的中断号和类型。  
        gpio@101f3000 {  
            compatible = "arm,pl061";  
            reg = <0x101f3000 0x1000  
                   0x101f4000 0x0010>;  
            interrupts = < 3 0 >;  
        }; //compatible: "arm,pl061" 表示这是一个与 ARM PL061 兼容的 GPIO 控制器。
           //reg: 列出了两个内存区域,通常一个用于控制寄存器,一个用于数据寄存器。
           //interrupts: 指定 GPIO 控制器使用的中断号和类型。
      
        intc: interrupt-controller@10140000 {  
            compatible = "arm,pl190";  
            reg = <0x10140000 0x1000 >;  
            interrupt-controller;  
            #interrupt-cells = <2>;  
        }; //compatible: "arm,pl190" 表示这是一个与 ARM PL190 兼容的中断控制器。
           //reg: 指定了中断控制器的基地址和内存区域大小。
           //interrupt-controller: 表明这个设备是一个中断控制器。
           //#interrupt-cells: 表明每个中断源配置需要两个单元。  
      
        spi@10115000 {  
            compatible = "arm,pl022";  
            reg = <0x10115000 0x1000 >;  
            interrupts = < 4 0 >;  
        }; //compatible: "arm,pl022" 表示与 ARM PL022 SPI 控制器兼容。
           //reg: 指定 SPI 控制器的基地址和内存区域大小。
           //interrupts: 指定 SPI 控制器使用的中断号和类型。
      
        external-bus {  
            #address-cells = <2>  
            #size-cells = <1>;  
            ranges = <0 0  0x10100000   0x10000     // Chipselect 1, Ethernet  
                      1 0  0x10160000   0x10000     // Chipselect 2, i2c controller  
                      2 0  0x30000000   0x1000000>; // Chipselect 3, NOR Flash  
        //描述了外部设备连接到系统的方式,包括以太网、I2C 控制器和 NOR Flash。
        //#address-cells 和 #size-cells: 指定地址和大小单元的格式,用于描述子节点。
        //ranges: 指定了设备如何映射到系统的地址空间。
            ethernet@0,0 {  
                compatible = "smc,smc91c111";  
                reg = <0 0 0x1000>;  
                interrupts = < 5 2 >;  
            };  
      
            i2c@1,0 {  
                compatible = "acme,a1234-i2c-bus";  
                #address-cells = <1>;  
                #size-cells = <0>;  
                reg = <1 0 0x1000>;  
                interrupts = < 6 2 >;  
                rtc@58 {  
                    compatible = "maxim,ds1338";  
                    reg = <58>;  
                    interrupts = < 7 3 >;  
                };  
            };  
      
            flash@2,0 {  
                compatible = "samsung,k8f1315ebm", "cfi-flash";  
                reg = <2 0 0x4000000>;  
            };  
        };  
};  
    //子设备
    //ethernet, i2c, 和 flash: 分别描述以太网控制器、I2C 控制器和 NOR Flash 设备的配置。
    //compatible: 提供了设备的兼容信息。
    //reg: 指定了设备在总线上的地址和映射大小。
    //interrupts: 指定了设备使用的中断号和类型。
    //I2C 控制器下还有一个 rtc 子设备,描述了一个实时时钟。


您需要登录后才可以回帖 登录 | 立即注册

本版积分规则