设备树

设备树什么是设备树设备树(DeviceTree)是用来描述板卡上的硬件资源信息的,包括外设控制器和各种外设所使用的硬件资源信息设备树的源文件名后缀是.dts/.dtsi,dtsi文件一般用来描述一些通用的硬件信息资源,然后会被dts文件引入,这样dts文件中就会包含dtsi文件中的内容设备树源文

大家好,欢迎来到IT知识分享网。

什么是设备树

  • 设备树(Device Tree)是用来描述板卡上的硬件资源信息的,包括外设控制器和各种外设所使用的硬件资源信息

  • 设备树的源文件名后缀是.dts/.dtsi, dtsi文件一般用来描述一些通用的硬件信息资源,然后会被dts文件引入,这样dts文件中就会包含dtsi文件中的内容

  • 设备树源文件在内核中的位置:/arch/arm(64)/boot/dts

  • dts源文件不能直接被内核驱动所使用,必须被编译成二进制文件才能被内核驱动使用,设备树二进制文件后缀名是dtb,使用dtc工具把dts文件编译成dtb文件

    graph LR dts —-dtc—> dtb

设备树语法

dts文件布局

/dts-v1/;                // 表示版本
[memory reservations]    // 格式为: /memreserve/ <address> <length>;
/ {
    [property definitions]
    [child nodes]
};

以上各项的含义:

名称 含义
/dts-v1/ 设备树文件的版本
memory reservations 指定保留内存,内核不会使用保留内存
/ 根节点(使用花括号表示属于根节点的内容)
property definitions 根节点的属性,用来描述硬件
child nodes 子节点(使用花括号表示属于孩子节点的内容)

设备节点

设备树中的基本单元被称为节点(node),格式为:

[label:] node-name[@unit-address] {
    [properties definitions]
    [child nodes]
};

label是标号,可以省略,label的作用是为了方便地引用node,比如:

/dts-v1/;
/ {
	uart0: uart@fe001000 {
        compatible="ns16550";
        reg=<0xfe001000 0x100>;
	};
};

可以使用下面2种方法来修改uart@fe001000这个node:
// 在根节点之外使用label引用node:

&uart0 {
    status = “disabled”;
};

或在根节点之外使用全路径:

&{/uart@fe001000}  {
    status = “disabled”;
};

属性(properties)

每个节点都有不同的属性,不同的属性又有不同的内容,属性都是键值对,值可以为空或任意的字节流

属性格式

  • 属性有值
    [label:] property-name = value;
    
  • 属性没有值
    [label:] property-name;
    

属性取值可以有四种

  1. arrays of cells(1个或多个32位数据, 64位数据使用2个32位数据表示)
    cell 就是一个32位的数据,一个或多个cell用尖括号括起来,并以空格隔开就可以作为一种合法的属性值
interrupts = <17 0xc>

64bit数据使用2个cell来表示,一个或多个cell用尖括号包围起来:

clock-frequency = <0x00000001 0x00000000>
  1. string(字符串),用双引号包围起来
compatible = "simple-bus";
  1. bytestring(1个或多个字节),用中括号包围起来
local-mac-address = [00 00 12 34 56 78];  // 每个byte使用2个16进制数来表示
local-mac-address = [000012345678];       // 每个byte使用2个16进制数来表示
  1. 以上三种值的混合,以逗号隔开
compatible = "ns16550", "ns8250";
example = <0xf00f0000 19>, "a strange property format";

一些常用的属性

compatible

compatible 属性也叫做“兼容性”属性,这是非常重要的一个属性!compatible 属性的值是一个字符串列表,compatible 属性用于将设备和驱动绑定起来。

“compatible”表示“兼容”,对于某个LED,内核中可能有A、B、C三个驱动都支持它,那可以这样写:

led {
    compatible = “A”, “B”, “C”;
};

内核启动时,就会为这个LED按这样的优先顺序为它找到驱动程序:A、B、C。

当该属性位于根节点时,用于指定内核中哪个machine_desc可以支持本设备,即当前设备与哪些平台兼容。其值的格式一般是”manufacturer,model”,其中manufacturer表示厂家,model表示型号(厂家的哪型产品)。

当该属性的值有多个字符串时,从左往右,从最特殊到最一般。举例来说,compatible = “samsung,smdk2416”, “samsung,s3c2416”;作为根节点的属性时,第一个字符串指示了一个具体的开发板型号,而第二个字符串要更一般,只指示了SoC的型号。在linux初始化时,会优先找支持”samsung,smdk2416″的machine_desc用以初始化硬件,找不到时才退而求其次”samsung,s3c2416″。

model

model属性与compatible属性有些类似,但是有差别。
compatible属性是一个字符串列表,表示你的硬件可以兼容A、B、C等驱动;
model用来准确地定义这个硬件是什么。
比如根节点中可以这样写:

/ {
    compatible = "samsung,smdk2440", "samsung,mini2440";
    model = "jz2440_v3";
};

它表示这个单板,可以兼容内核中的“smdk2440”,也兼容“mini2440”。
从compatible属性中可以知道它兼容哪些板,但是它到底是什么板?用model属性来明确。

#address-cells、#size-cells

cell指一个32位的数值
address-cells:address要用多少个32位数来表示
size-cells:size要用多少个32位数来表示

比如一段内存,怎么描述它的起始地址和大小?
下例中,address-cells为1,所以reg中用1个数来表示地址,即用0x80000000来表示地址;size-cells为1,所以reg中用1个数来表示大小,即用0x20000000表示大小:

/ {
#address-cells = <1>;
#size-cells = <1>;
memory {
    reg = <0x80000000 0x20000000>;
    };
};

status

status 属性是和设备状态有关的,status 属性值是字符串

&uart1 {
    status = "disabled";
};

status 可选的状态如下:

含义
“okay” 表明设备是可操作的。
“disabled” 表明设备当前是不可操作的,但是在未来可以变为可操作的
“fail” 发生了严重错误,需修复
“fail-sss” 发生了严重错误,需修复;sss表示错误信息

phandle

该属性可以为节点指定一个全局唯一的数字标识符。这个标识符可以被需要引用该节点的另一个节点使用。举例来说,现有一个中断控制器:

pic@10000000 {
    phandle = <1>;
    interrupt-controller;
};

还有一个可以产生中断的设备,且这个设备的中断信号线连接到了上述中断控制器,为了描述清楚这种关系,该设备的设备节点就需要引用中断控制器的节点:

another-device-node {
    interrupt-parent = <1>; /* 数字1就唯一标识了节点pic@10000000 */
};

interrupt-controller

这是一个没有值的属性,用在中断控制器的设备节点中,以表明这个节点描述的是一个中断控制器。

interrupt-parent

该属性用于可以产生中断,且中断信号连接到某中断控制器的设备的设备节点,用于表示该设备的中断信号连接到了哪个中断控制器。该属性的值通常是中断控制器设备节点的数字标识(phandle),具体示例在上文已经出现过了。

reg

reg属性描述了设备资源在其父总线定义的地址空间内的地址。reg 属性的值一般是(address,length)对,该属性使用一对或多对(地址,长度)来描述设备所占的地址空间。至于地址和长度使用多少个cell来表示呢?这取决于父节点的#address-cells、#size-cells属性的值。

举个例子,当:

#address-cells = <1>;
#size-cells = <1>;

那么reg = <0x3000 0x20 0xFE00 0x100>,表示该属性所属的设备占据了两块内存空间,第一块是以0x3000为起始的32字节内存块;第二块是以0xFE00为起始的256字节内存块。

/aliases

/aliases节点应当作为根节点的孩子节点,用于定义一个或多个别名属性,每条别名属性会为一个设备节点的路径名设置一个别名,别名即为别名属性的属性名,属性值则是设备节点的路径名。如下面这个例子所示:
aliases { serial0 = "/simple-bus@fe000000/serial@llc500"; ethernet0 = "/simple-bus@fe000000/ethernet@31c000"; };

/chosen

/chosen节点应当用作根节点的孩子节点,有以下可选属性:

  • bootargs
  • stdout-path
  • stdin-path

顾名思义,该节点可以指定启动参数、标准输出和标准输入,一个例子如下:

/ {
	......
	chosen {
		bootargs = "root=/dev/nfs rw nfsroot=192.168.1.1 console=ttyS0,115200";
	};
	......
};

向节点追加或修改内容

要向节点中追加或修改节点中的属性,可以对节点使用引用的方式来处理。
比如原始的i2c1节点是:

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";
};

要对i2c1节点做属性的追加和修改,使用如下方式:

&i2c1 {
    /* 要追加或修改的内容 */
};

&i2c1 表示使用引用的方式访问 i2c1 这个 label 所对应的节点

修改后的设备树代码如下:

&i2c1 {
    clock-frequency = <100000>;
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_i2c1>;
    status = "okay";

    mag3110@0e {
        compatible = "fsl,mag3110";
        reg = <0x0e>;
        position = <2>;
    };

    fxls8471@1e {
        compatible = "fsl,fxls8471";
        reg = <0x1e>;
        position = <0>;
        interrupt-parent = <&gpio5>;
        interrupts = <0 8>;
    };
};

其中:
clock-frequency 就是新添加的属性。
status 属性的值由原来的 disabled 改为 okay
mag3110 和 fxls8471 是新增加的2个子节点

编写设备树

在DTS文件中包含其他文件

编写设备树文件时,我们通常会把多种设备的共性抽出来,写在DTSI文件(后缀为.dtsi)中,其语法与DTS文件一样。比如,多款使用了am335x的板子,因为使用了同一款SoC,描述设备时肯定会有一些相同的部分,可以把这部分抽出来,写到am335x.dtsi中,然后在具体的某型板子的设备树中包含相应的DTSI文件,包含的方式有:

/include/ “xxx.dtsi”
#include “xxx.dtsi”

设备树编译器还支持c语言的头文件,因此,如果有需要可以定义一些宏并在设备树文件中使用。

如何在设备树文件中描述设备

设备树写出来是给驱动程序看的,也就是说驱动程序怎么写的,相应的设备树就该怎么写;或者反过来,先约定好设备树怎么写,在相应的设计驱动。驱动和设备树有着对应的关系,这种对应关系也被称为bindings。具体的:

对于上游芯片厂商,应当按照devicetree-specification推荐的设备树写法,遵守各种约定,确定好如何规范的描述设备,并提供相应的驱动程序。devicetree-specification-v0.3的第四章给出了一些推荐的做法。

对于下游产品厂商,当使用芯片厂商的芯片做产品时,芯片厂商通常会提供驱动程序和设备树文件编写的参考文档,这些文档位于linux内核源码树的Documentation/devicetree/bindings目录下。如果芯片厂商没提供相应文档的话,就要读驱动的源码,知道驱动怎么写的,自然也就知道如何写设备树了。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/30373.html

(0)

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信