1.概念
linux設備樹是用於描述硬件及部分啟動指令的文件,由bootloader傳遞給內核(U-boot需要在config文件中加入"#define CONFIG_OF_LIBFDT"),
內核分析此文件而對硬件使用不同的參數。
比如兩塊開發板僅僅是內存容量不一樣,那么就只需要修改設備樹中對內存容量的描述即可,
而不需要重新編譯內核。
與設備樹相關的文件有如下幾種:
DTS(device tree source)
.dts文件,就是ASCII字符串形式的文本文件,直接由開發人員修改。
對於ARM架構而言,這些文件位於:arch/arm/boot/dts 目錄下。
DTSI(device tree source include)
.dtsi文件,用於被.dts文件所包含。並且.dtsi文件也可以包含.dtsi文件。與c/c++ 包含頭文件一個道理。
此文件包含了很多設備下所共有的許多配置。
在.dts文件下,使用"#include "file.dtsi"" 或"/include/ "file.dtsi""來包含。
DTB(device tree blob)
通過工具提前將DTS文件編譯為.dtb二進制文件,bootloader傳遞此文件給內核,這樣內核的解析速度才快。
DTC(device tree compiler)
將.dts文件編譯為.dtb的工具,其源碼位於scripts/dtc目錄下,此工具根據用戶設定的SOC來確定編譯哪種目標板。
Binding
對於設備樹中的節點及屬性具體描述文檔,位於Document/devicetree/bindings,、
需要仔細閱讀!需要仔細閱讀!需要仔細閱讀!
2.規則
設備樹的結構是由節點和節點中的屬性構成的,這就如同c/c++中結構體名稱和元素名稱及元素值的關系一樣。
#include "skelston.dtsi" /*包含*/ /{ node{ a-string-property = "string"; }; }; /* "/" 代表根節點,根節點是設備樹的起始節點,一個設備文件中必須且僅有一個根節點,"node"是一個子節點名, "a-string-property"是一個屬性名,"string"是屬性值。 */
2.1 節點
2.1.1節點命名及路徑
節點命名可以有如下幾種方式:
1、以"設備名"為節點名
比如設備DM9000,對應的節點路徑為:/dm9000
/{
...
dm9000{
...
};
...
};
2、以"設備名@I/O地址"為節點名:
比如設備DM9000位於I/O地址為0x8000 0000,對應的節點路徑為:/dm9000@80000000
注意:這種方式下,若兩個節點具有相同的設備名和不同的I/O地址,也同樣代表兩個不同的設備!
/{ ... dm9000@80000000{ ... }; ... };
2.1.2節點引用
如同linux中可以為命令命名別名(alias)一樣,節點也可以先命名別名再引用。
注意:在節點引用的同時,其內容等同於被引用過來了。
/{ ... dm9000:dm9000@80000000{ ... }; ... &dm9000{ }; }; /* &dm9000就等價於 dm9000@80000000 */
2.1.3節點合並
若同一設備樹中有相同的節點名及地址時,節點的內容會合並。
若節點內容中出現了相同的屬性,則新屬性值替換掉老的屬性值。
比如在petalinux中可以修改頂層的設備樹文件,將新的設置信息與老的合並或替換。而不用關心以前默認的設定值。
2.2屬性
2.2.1屬性的內容
屬性的內容比較靈活,可以為:
1、空(比如:an-empty-proerty;)
2、字符串(比如:a-string-property = "A string";)
3、字符串數組(比如:a-string-list-property = "first string","second string";)
4、整數(比如:a-cell-property = <1234>;)
5、16進制數(比如:a-byte-data-property = [0x01 0x02 0x03 0x04];)
2.2.2常用的屬性名及內容的意義
有關屬性名及內容更為具體的意義和使用方式,需要仔細反復閱讀Documentation/devicetree/目錄下的相關文件!
下面列出一些常用的屬性:
1、compatible(兼容)
compatible的內容為字符串數組,其形式為:<manufacturer>,<model>。
其意義代表設備"廠商和哪個具體的型號"或者"具體設備名稱和兼容設備",linux內核中的解析代碼,通過節點此屬性來確定這個具體的驅動匹配,
比如在zynq-7000.dtsi中根節點屬性:
compatible = "xlnx,zynq-7000"
在zynq-zed.dts中qspi結點中flash子節點的屬性:
/{ ... &qspi{ ... flash@0{ compatible = "n25q128a11"; ... } }; ... };
2、reg(設備地址)
reg的內容一般為16進制數,其形式為:<address 1 length 1 [address 2 length 2] [address 3 length 3] ...>,
address代表此設備相對於父節點的偏移地址
length代表設備可以操作的地址范圍,也就是地址大小
reg中的address和length數量的多少,是由#address-cells和#size-cells兩個屬性來決定子節點的reg內容。
比如:
在zynq-70000.dtsi文件中 cpus節點定義#address-cells = 1,#size-cells=0,代表子節點的reg屬性中地址1位,大小位為空。
/{ ... cpus{ #address-cells = <1>; #size-cells = <0>; cpu@0{ .... reg = <0>; .... }; cpu@1{ .... reg = <1>; .... }; }; };
在ambs節點中定義#address-cells = 1,#size-cells = 1,代表子節點reg屬性中地址和大小都為1位。
/{ amba:amba{ .... #address-cells = <1>; #size-cells = <1>; .... adc:adc@f8007100{ .... reg = <0xf8007100 0x20>; .... }; gpio0:gpio@e000a000{ ... reg = <0xe000a000 0x1000>; ... }; }; };
3、interrupt-controller(中斷控制器)
此屬性為空,通過此屬性以表明此設備具有中斷相關功能。
4、#interrupt-cells(表明interrupts屬性中地址大小)
與#size-cells相似
5、interrupt-parent(指明此控制器所依附的中斷控制器)
若子節點中沒有指明此屬性,則從父節點中繼承。
比如zynq-70000.dtsi中的gpio控制器節點:
/{ .... gpio0:gpio@e00a000{ compatible = "xlnx,zynq-gpio-1.0"; #gpio-cells = <2>; #interrupt-cells = <2>; clocks = <&clkc 42>; gpio-controller; interrupt-controller; interrupt-parent = <&intc>; interrupts = <0 20 4>; reg = <0xe00a000 0x1000>; }; .... };