設備樹的官方文檔: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)>; };