设备树的规范(dts)

设备树的官方文档:node

https://www.devicetree.org/specifications/linux

1、理论部分ide

如何看下面这张图:函数

1)从根节点开始看起,即 /布局

2)在根节点中有属性以及设备节点名称spa

3)属性的格式有两种形式:property-name = value;property-name ;(一个有值,一个没值)命令行

   当property-name = value时,value的取值有三种形式code

4)设备节点(child nodes)的格式orm

 总结:blog

(1) 语法:
Devicetree node格式:
[label:] node-name[@unit-address] {
  [properties definitions]
  [child nodes]
};

Property格式1:
[label:] property-name = value;

Property格式2(没有值):
[label:] property-name;

Property取值只有3种:
arrays of cells         (1个或多个32位数据, 64位数据使用2个32位数据表示),
string                     (字符串),
bytestring              (1个或多个字节)

示例:
a. Arrays of cells : cell就是一个32位的数据
interrupts = <17 0xc>;

b. 64bit数据使用2个cell来表示:
clock-frequency = <0x00000001 0x00000000>;

c. A null-terminated string (有结束符的字符串):
compatible = "simple-bus";

d. A bytestring(字节序列) :
local-mac-address = [00 00 12 34 56 78]; // 每一个byte使用2个16进制数来表示
local-mac-address = [000012345678]; // 每一个byte使用2个16进制数来表示

e. 能够是各类值的组合, 用逗号隔开:
compatible = "ns16550", "ns8250";
example = <0xf00f0000 19>, "a strange property format";

(2) DTS文件布局(layout):


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

(3) 特殊的、默认的属性:
a. 根节点:
#address-cells    // 在它的子节点的reg属性中, 使用多少个u32整数来描述地址(address)
#size-cells      // 在它的子节点的reg属性中, 使用多少个u32整数来描述大小(size)

例子:

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

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

在子节点的reg属性中,0x30000000表示地址,0x4000000来表示大小。我凭什么知道在reg中用一个32位整数来描述地址,一个32位整数来描述大小。就是经过

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

进行指定的。


compatible     // 定义一系列的字符串, 用来指定内核中哪一个machine_desc能够支持本设备
           // 即这个板子兼容哪些平台
           // uImage : smdk2410 smdk2440 mini2440 ==> machine_desc 。一个uImage能够支持多种单板,好比说    smdk24十、smdk2440、mini2440。每种单板在内核中都有一个对应的machine_desc结构体,里面会有不一样的初始化函数。所以利用compatible这个属性能够选择单板,让内核去执行对应的初始化函数。

举例:

compatible = "samsung,smdk2440";  经过这样指定,内核就会去执行smdk2440中的初始化函数

compatible能够是一个或多个字符串。好比说compatible = "samsung,smdk2440"  "samsung,smdk24xx"  

smdk2440就更加具体,s3c24xx就比较普遍些,能够适配更多的单板。使用设备树时,优先去内核中寻找支持smdk2440的machine_desc,若是找不到的话,再去寻找支持smdk24xx的machine_desc。优先选择第一项,若是没有,再日后选择。

model    // 咱这个板子是什么
         // 好比有2款板子配置基本一致, 它们的compatible是同样的
        // 那么就经过model来分辨这2款板子

b. /memory
device_type = "memory";    //这是约定俗称的,必须写这个。
reg // 用来指定内存的地址、大小

c. /chosen
bootargs // 内核command line参数, 跟u-boot中设置的bootargs做用同样

例子:

chosen {
  bootargs = "noinitrd root=/dev/mtdblock4 rw init=/linuxrc console=ttySAC0,115200";   //内核启动时的命令行参数
};

d. /cpus
/cpus节点下有1个或多个cpu子节点, cpu子节点中用reg属性来标明本身是哪个cpu
既然谈到了reg属性,那么一定少不了两个东西:#address-cells和#size-cells

因此 /cpus 中有如下2个属性:
#address-cells // 在它的子节点的reg属性中, 使用多少个u32整数来描述地址(address)

#size-cells   // 在它的子节点的reg属性中, 使用多少个u32整数来描述大小(size)
         // 必须设置为0


e. /cpus/cpu*
device_type = "cpu";   //在cpus/cpu这个子节点中,必须有一个device_type = "cpu"
reg          // 代表本身是哪个cpu

(4) 引用其余节点:

a. phandle : // 节点中的phandle属性, 它的取值必须是惟一的(不要跟其余的phandle值同样)

pic@10000000 {
  phandle = <1>;
  interrupt-controller;    //代表pic@10000000是一个中断控制器,
};

another-device-node {         //这个设备产生了中断,要传给中断控制器,就须要在能发出中断的这个节点another-device-node中,指定                                               //它的interrupt-parent。那么在这个地方如何引用中断控制器呢?有两种方法:能够在中断控制器里面使用                                               //phandle=某个值,这个值是惟一的。好比说有其余的节点里面phandle= <1>,那么此处的phandle就不                                                 //能  等于1。
  interrupt-parent = <1>; // 使用phandle值为1来引用上述节点,这种方法有点麻烦。
};

b. label:          //第二种方法

PIC: pic@10000000 {          //该节点为一个中断控制器。若是在其余节点中要引用此节点的话,可使用它的lable。
  interrupt-controller;
};

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

注意第二种方法的实现方式其实和第一种是相同的,编译dts文件时,编译器会在中断控制器所在的节点中加入一个phandle= <xxxx>。将interrupt-parent = <&PIC>替换为interrupt-parent = <xxxx>;这都是编译器帮咱们作的。

2、代码

设备树文件里面,它把一些公共的部分写为dtsi文件,dts文件能够去包含dtsi文件,二者的语法格式是同样的。

一、override问题

jz2440.dtsi

 1 // SPDX-License-Identifier: GPL-2.0
 2 /*
 3  * SAMSUNG SMDK2440 board device tree source  4  *  5  * Copyright (c) 2018 weidongshan@qq.com  6  * dtc -I dtb -O dts -o jz2440.dts jz2440.dtb  7  */
 8  
 9 #define S3C2410_GPA(_nr)    ((0<<16) + (_nr))
10 #define S3C2410_GPB(_nr)    ((1<<16) + (_nr))
11 #define S3C2410_GPC(_nr)    ((2<<16) + (_nr))
12 #define S3C2410_GPD(_nr)    ((3<<16) + (_nr))
13 #define S3C2410_GPE(_nr)    ((4<<16) + (_nr))
14 #define S3C2410_GPF(_nr)    ((5<<16) + (_nr))
15 #define S3C2410_GPG(_nr)    ((6<<16) + (_nr))
16 #define S3C2410_GPH(_nr)    ((7<<16) + (_nr))
17 #define S3C2410_GPJ(_nr)    ((8<<16) + (_nr))
18 #define S3C2410_GPK(_nr)    ((9<<16) + (_nr))
19 #define S3C2410_GPL(_nr)    ((10<<16) + (_nr))
20 #define S3C2410_GPM(_nr)    ((11<<16) + (_nr))
21 
22 /dts-v1/; 23 
24 / { 25     model = "SMDK24440"; 26     compatible = "samsung,smdk2440"; 27 
28     #address-cells = <1>; 29     #size-cells = <1>; 30         
31     memory {  /* /memory */
32         device_type = "memory"; 33         reg =  <0x30000000 0x4000000 0 4096>; 34  }; 35 
36     
37 /*
38  cpus { 39  cpu { 40  compatible = "arm,arm926ej-s"; 41  }; 42  }; 43 */    
44  chosen { 45         bootargs = "noinitrd root=/dev/mtdblock4 rw init=/linuxrc console=ttySAC0,115200"; 46  }; 47 
48     
49  led { 50         compatible = "jz2440_led"; 51         pin = <S3C2410_GPF(5)>; 52  }; 53 };

原本led默认的pin = <S3C2410_GPF(5)>;可是我不想使用这个引脚,而且我也不想去修改这个dtsi文件。怎么办?

能够在jz2440_dts文件中将其覆盖。以下所示:

// SPDX-License-Identifier: GPL-2.0 /* * SAMSUNG SMDK2440 board device tree source * * Copyright (c) 2018 weidongshan@qq.com * dtc -I dtb -O dts -o jz2440.dts jz2440.dtb */
 
/dts-v1/; #include "jz2440.dtsi"

/ { led {  pin = <S3C2410_GPF(6)>; }; };

二、lable问题

上面的这个例子中,在dts文件中引用在dtsi中定义的led节点,是很是麻烦的。

/  {

  led {

  };

}

此时lable就派上用场了。

// SPDX-License-Identifier: GPL-2.0 /* * SAMSUNG SMDK2440 board device tree source * * Copyright (c) 2018 weidongshan@qq.com * dtc -I dtb -O dts -o jz2440.dts jz2440.dtb */
 
#define S3C2410_GPA(_nr)    ((0<<16) + (_nr))
#define S3C2410_GPB(_nr)    ((1<<16) + (_nr))
#define S3C2410_GPC(_nr)    ((2<<16) + (_nr))
#define S3C2410_GPD(_nr)    ((3<<16) + (_nr))
#define S3C2410_GPE(_nr)    ((4<<16) + (_nr))
#define S3C2410_GPF(_nr)    ((5<<16) + (_nr))
#define S3C2410_GPG(_nr)    ((6<<16) + (_nr))
#define S3C2410_GPH(_nr)    ((7<<16) + (_nr))
#define S3C2410_GPJ(_nr)    ((8<<16) + (_nr))
#define S3C2410_GPK(_nr)    ((9<<16) + (_nr))
#define S3C2410_GPL(_nr)    ((10<<16) + (_nr))
#define S3C2410_GPM(_nr)    ((11<<16) + (_nr))

/dts-v1/; / { model = "SMDK24440"; compatible = "samsung,smdk2440"; #address-cells = <1>; #size-cells = <1>; memory { /* /memory */ device_type = "memory"; reg =  <0x30000000 0x4000000 0 4096>; }; /* cpus { cpu { compatible = "arm,arm926ej-s"; }; }; */ chosen { bootargs = "noinitrd root=/dev/mtdblock4 rw init=/linuxrc console=ttySAC0,115200"; }; LED: led { compatible = "jz2440_led"; pin = <S3C2410_GPF(5)>; }; };

在dts文件中,

// SPDX-License-Identifier: GPL-2.0 /* * SAMSUNG SMDK2440 board device tree source * * Copyright (c) 2018 weidongshan@qq.com * dtc -I dtb -O dts -o jz2440.dts jz2440.dtb */
 
/dts-v1/; #include "jz2440.dtsi"
&LED { pin = <S3C2410_GPF(6)>; };
相关文章
相关标签/搜索