1. 程式人生 > 其它 >【轉載】Linux下裝置樹內容(詳細)總結及示例解析

【轉載】Linux下裝置樹內容(詳細)總結及示例解析

轉載:https://blog.csdn.net/Luckiers/article/details/124772722

參考文章:

韋東山老師裝置樹視訊筆記整理

https://blog.csdn.net/qq_31418645/article/details/100022042

文章目錄
一、簡介
二、裝置樹基礎內容
2.1 裝置樹檔案存放路徑
2.2 DTS、DTB和DTC關係
2.3 傳統驅動程式碼和使用裝置樹的對比
三、裝置樹內容屬性介紹
3.1 節點名稱
3.2 compatible
3.3 model 屬性
3.4 status 屬性
3.5 #address-cells 和 #size-cells 屬性
3.6 ranges 屬性
3.7 aliases 節點
3.8 chosen 節點
四、裝置樹檔案內容示例解析
4.1 裝置樹關鍵內容解析
一、簡介
裝置樹是在PowerPC平臺最先使用,後來2011年3月份Linux創始人Linus Torvalds在郵件建議ARM社群也使用裝置樹的方式去描述板級結構。所以裝置樹其實就是描述開發板上的硬體資訊,由於其結構就像現實世界的大樹一樣,所以就將這種結構叫裝置樹,如下圖所示。

二、裝置樹基礎內容
2.1 裝置樹檔案存放路徑
dts原始碼都在對應的架構目錄下,如arm平臺arch/arm/boot/dts,對應的檔案主要有1個dts檔案+n個dtsi檔案,它們編譯而成的dtb檔案就是真正的裝置樹。
soc廠商會把soc公共的特性和多塊開發板公用的特性提煉為dtsi,而dts則負責描述某個具體的產品(開發板)的特性。dts直接或間接的包含多個dtsi(類似於c語言的標頭檔案),就體現了一個完整的產品(開發板)所有的特性。以solidrun公司的hummingboard為例,其組成為

imx6dl-hummingboard.dts
|_imx6dl.dtsi
| |_imx6qdl.dtsi
|_imx6qdl-microsom.dtsi
|_imx6qdl-microsom-ar8035.dtsi


2.2 DTS、DTB和DTC關係
DTS(devcie tree source):裝置樹原始碼檔案
DTB(device tree binary):將 .dts 編譯後得到二進位制檔案,下載到 DDR 中的是 .dtb 檔案
DTC(device tree compiler):將 .dts 編譯為 .dtb 的編譯工具,它有個資料夾,經過編譯後得到 DTC

2.3 傳統驅動程式碼和使用裝置樹的對比
傳統方式:
(1)程式碼冗餘
在沒有使用裝置樹的時候,有關板級的硬體資訊都被硬編碼在核心中,這就導致了核心中描述板級硬體的程式碼過於龐大,不利於閱讀。以arm架構為例,通常這些硬體資訊會放在/arch/arm/mach-xxx和/arch/arm/plat-xxx裡面。

(2)修改麻煩
在核心中有一種叫匯流排的模型,這種模型的作用是將裝置資訊與驅動進行分離,在沒有使用裝置樹的情況下,這裡的裝置資訊就被硬編碼到/arch/arm/mach-xxx和/arch/arm/plat-xxx中。這就會導致一種不好的結果,當你修改了某個裝置的資訊時,你就需要重新編譯核心並把核心燒到系統中。

裝置樹的優點:
在使用裝置樹後,核心中就不再需要那些硬體資訊了,描述硬體的資訊都會被統一放到/arch/arm/boot/dts的裝置樹檔案中,這樣就可以減少程式碼的冗餘。
當你需要修改裝置的硬體資訊時,只需要在修改裝置樹之後,對裝置樹進行編譯並放到系統中,uboot就會將裝置樹的地址告訴Linux核心,讓Linux核心到相應的記憶體地址去解析裝置樹資訊,不再需要重新編譯核心。

三、裝置樹內容屬性介紹
3.1 節點名稱
node-name@unit-address //node-name:節點名字 unit-address:表示暫存器基地址或裝置地址,如下serial@101f0000
label:node-name@unit-address // 引入label目的就是為了方便便訪問節點,可以直接通過&label來訪問這個

serial@101f0000 {
compatible = "arm,pl011";
reg = <0x101f0000 0x1000 >;
interrupts = < 1 0 >;


3.2 compatible
compatible 屬性值為字串列表,⽤於將裝置和驅動繫結起來,字串列表⽤於選擇裝置所要使用的驅動程式

"manufacturer,model" //anufacturer :廠商 model:模組對應的驅動名
1
一般驅動程式檔案中都會有一個 OF 匹配表,此 OF 匹配表儲存著一些 compatible 值,如果裝置節點的 compatible 屬性值和 OF 匹配表中的任何一個值相等,那麼就表示裝置可以使用這個驅動。

3.3 model 屬性
model 屬性:描述裝置模組資訊,比如名字什麼的,如:model = “wm8960-audio”。

3.4 status 屬性
status 屬性:描述裝置狀態,如:okay - 裝置可操作,disabled - 裝置不可操作

3.5 #address-cells 和 #size-cells 屬性
#address-cells 和 #size-cells 描述⼦節點應如何編寫 reg 屬性值,一般 reg 屬性是某個外設的暫存器地址範圍資訊。

3.6 ranges 屬性
ranges它是一個地址對映/轉換表,如果 ranges 屬性值為空值,說明子地址空間和父地址空間完全相同,不需要進行地址轉換。

3.7 aliases 節點
用 aliases 節點給多個同類型的控制器分配唯一編號,便於Linux核心區分。在Linux啟動時會解析aliases節點。

3.8 chosen 節點
chosen 並不是一個真實的裝置,主要用於將 uboot 中的 bootargs 環境變數值傳遞給 Linux 核心作為命令列引數

四、裝置樹檔案內容示例解析
/ {
compatible = "acme,coyotes-revenge";
#address-cells = <1>;
#size-cells = <1>;
interrupt-parent = <&intc>;

cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
compatible = "arm,cortex-a9";
reg = <0>;
};
cpu@1 {
compatible = "arm,cortex-a9";
reg = <1>;
};
};

serial@101f0000 {
compatible = "arm,pl011";
reg = <0x101f0000 0x1000 >;
interrupts = < 1 0 >;
};

serial@101f2000 {
compatible = "arm,pl011";
reg = <0x101f2000 0x1000 >;
interrupts = < 2 0 >;
};

gpio@101f3000 {
compatible = "arm,pl061";
reg = <0x101f3000 0x1000
0x101f4000 0x0010>;
interrupts = < 3 0 >;
};

intc: interrupt-controller@10140000 {
compatible = "arm,pl190";
reg = <0x10140000 0x1000 >;
interrupt-controller;
#interrupt-cells = <2>;
};

spi@10115000 {
compatible = "arm,pl022";
reg = <0x10115000 0x1000 >;
interrupts = < 4 0 >;
};

external-bus {
#address-cells = <2>
#size-cells = <1>;
ranges = <0 0 0x10100000 0x10000 // Chipselect 1, Ethernet
1 0 0x10160000 0x10000 // Chipselect 2, i2c controller
2 0 0x30000000 0x1000000>; // Chipselect 3, NOR Flash

ethernet@0,0 {
compatible = "smc,smc91c111";
reg = <0 0 0x1000>;
interrupts = < 5 2 >;
};

i2c@1,0 {
compatible = "acme,a1234-i2c-bus";
#address-cells = <1>;
#size-cells = <0>;
reg = <1 0 0x1000>;
interrupts = < 6 2 >;
rtc@58 {
compatible = "maxim,ds1338";
reg = <58>;
interrupts = < 7 3 >;
};
};

flash@2,0 {
compatible = "samsung,k8f1315ebm", "cfi-flash";
reg = <2 0 0x4000000>;
};
};
};


4.1 裝置樹關鍵內容解析
(1)address、length和#address-cells 、#size-cells的關係
其中reg的組織形式為reg = ,其中的每一組address length表明了裝置使用的一個地址範圍。address為1個或多個32位的整型(即cell),而length則為cell的列表或者為空 (若#size-cells = 0)。address 和 length 欄位是可變長的,父結點的#address-cells和#size-cells分別決定了子結點的reg屬性的address和length欄位的長 度。在本例中,root結點的#address-cells = <1>;和#size-cells = <1>;決定了serial、gpio、spi等結點的address和length欄位的長度分別為1。cpus 結點的#address-cells = <1>;和#size-cells = <0>;決定了2個cpu子結點的address為1,而length為空,於是形成了2個cpu的reg = <0>;和reg = <1>;。external-bus結點的#address-cells = <2>和#size-cells = <1>;決定了其下的ethernet、i2c、flash的reg欄位形如reg = <0 0 0x1000>;、reg = <1 0 0x1000>;和reg = <2 0 0x4000000>;。其中,address欄位長度為0,開始的第一個cell(0、1、2)是對應的片選,第2個cell(0,0,0)是相 對該片選的基地址,第3個cell(0x1000、0x1000、0x4000000)為length。特別要留意的是i2c結點中定義的 #address-cells = <1>;和#size-cells = <0>;又作用到了I2C總線上連線的RTC,它的address欄位為0x58,是裝置的I2C地址。

(2)中斷號和電平觸發方式

interrupts = < 6 2 >; //中斷號為6,下降沿觸發

#電平觸發方式定義
1 = low-to-high edge triggered
2 = high-to-low edge triggered
4 = active high level-sensitive
8 = active low level-sensitive

(3)驅動獲取裝置樹內容的常用函式
裝置樹描述了裝置的詳細資訊,我們在編寫驅動時需要獲取到這些資訊,Linux核心給我們提供了一系列的函式來獲取裝置樹中的節點或者屬性資訊,核心啟動時會解析.dtb檔案,從而獲取裝置樹中各個節點的資訊,並且在根檔案系統的/proc/device-tree目錄下根據節點名字建立不同資料夾。

查詢節點:of_find_node_by_path 函式,通過指定全路徑來查詢指定節點。
提取屬性值:of_find_property 函式 ,獲取到的值儲存到了 property 結構體中。
讀取屬性中字串值:of_property_read_string 函式。
讀取屬性中陣列資料:of_property_read_u32_array 函式,常用於一次讀取出 reg 屬性中的所有資料。
直接記憶體對映:of_iomap 函式,獲取記憶體地址所對應的虛擬地址

(4)繫結資訊文件查詢
我們往往不知道如何在裝置樹中新增一個硬體對應的節點,此時我們可以參考Linux核心原始碼中有詳細的.txt文件描述瞭如何新增節點,這些.txt文件叫做繫結文件。
路徑:/Documentation/devicetree/bindings