設備樹的規範(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)>; };
相關文章
相關標籤/搜索