Linux裝置樹使用
本頁面介紹瞭如何為新machine編寫裝置樹檔案。它旨在提供裝置樹概念的概述以及它們如何用於描述machine。
有關裝置樹資料格式的完整技術說明,請參閱ePAPR v1.1規範。ePAPR規範比本頁面介紹的基本主題包含更多詳細資訊,請參閱此頁面以獲取本頁未涵蓋的更高階用法。ePAPR目前正在使用Devicetree規範文件的新名稱進行更新。
1.基本資料格式
裝置樹是由節點和屬性組成的樹型結構。屬性是鍵-值對的形式,節點可以包含屬性和子節點。例如,以下是.dts格式的簡單裝置樹:
/dts-v1/; //裝置樹的版本號 / { node1{ //節點 a-string-property = "A string"; a-string-list-property = "first string", "second string"; // hex is implied in byte arrays. no '0x' prefix is required a-byte-data-property = [01 23 34 56]; child-node1{ //子節點 first-child-property; second-child-property = <1>; a-string-property = "Hello, world"; }; child-node2{ //子節點 }; }; node2{ //子節點 an-empty-property; a-cell-property = <1 2 3 4>; /* each number (cell) is a uint32 */ child-node1{ //子節點 }; }; };
這個裝置樹檔案顯然沒有實際用處,因為它沒有描述任何東西,但它確實顯示了節點和屬性的結構。包括:
一個根節點:"/"; 兩個子節點:"node1"和"node2"; node1的子節點:"child-node1"和"child-node2"; 各個節點的屬性。
屬性是簡單的鍵值對形式,其中值可以為空或包含任意位元組流。雖然資料型別未編碼到資料結構中,但有一些基本資料表示可以在裝置樹原始檔中表示。
文字字串用雙引號表示: string-property = "a string"; 'Cells'是由尖括號分隔的32位無符號整數: cell-property = <0xbeef 123 0xabcd1234>; 二進位制資料用方括號分隔: binary-property = [0x01 0x23 0x45 0x67]; 可以使用逗號將不同表示形式的資料連線在一起: mixed-property = "a string", [0x01 0x23 0x45 0x67], <0x12345678>; 還可以使用逗號建立字串列表: string-list = "red fish", "blue fish";
2.基本概念
要了解裝置樹的使用方式,我們將從一臺簡單的機器開始,並構建一個裝置樹來逐步描述它。
考慮以下設想的機器(基於ARM Versatile),由"Acme"製造並命名為"Coyote's Revenge":
一個32位ARM CPU; 處理器本地匯流排連線到記憶體對映的串列埠,spi匯流排控制器,i2c控制器,中斷控制器和外部匯流排橋; 基於0地址的256MB SDRAM; 2個基於0x101F1000和0x101F2000的串列埠; GPIO控制器基地址為0x101F3000; 基於0x10170000地址的SPI控制器,具有以下器件; 帶有SS引腳的MMC插槽連線到GPIO#1; 外部匯流排橋接器具有以下裝置: SMC SMC91111乙太網裝置連線到外部匯流排,基地址為0x10100000; i2c控制器基地址為0x10160000,具有以下裝置: Maxim DS1338實時時鐘。從地址為1101000(0x58); 基地址為0x30000000的64MB NOR快閃記憶體。
初始基本dts框架:
第一步是為machine設定骨架結構。這是有效裝置樹所需的最小結構。在此階段,您需要唯一標識機器。
/ DTS-V1 /;
/ {
compatible =“acme,coyotes-revenge”;
};
compatible指定系統的名稱。它包含一個"<manufacturer>,<model>"形式的字串。重要的是指定確切的裝置,幷包含製造商名稱以避免名稱空間衝突。由於作業系統將使用該compatible值來決定如何在機器上執行,將正確的資料放入此屬性非常重要。
從理論上講,compatible是作業系統唯一識別機器所需的資料。如果所有機器細節都是硬編碼的,那麼作業系統可能會專匹配對上層的compatible屬性中的"acme,coyotes-revenge"。
CPU的設定:
/ DTS-V1 /;
/ {
compatible =“acme,coyotes-revenge”;
cpus {
cpu @ 0 {
compatible =“arm,cortex-a9”;
};
cpu @ 1 {
compatible =“arm,cortex-a9”;
};
};
};
每個cpu節點中的compatible屬性是一個字串,它指定表單中的確切cpu模型<manufacturer>,<model>,就像頂層的compatible屬性一樣。稍後將向cpu節點新增更多屬性,但我們首先需要討論更多基本概念。
節點名稱:
值得花點時間談談命名約定。每個節點必須有一個名稱,格式為:<name>[@<unit-address>]。<name>是一個簡單的ascii字串,最多可以包含31個字元。通常,節點根據它代表的裝置型別命名。即,3com乙太網介面卡的節點將使用該名稱ethernet,而不是3com509。如果節點描述的是具有地址的裝置,則包括地址。通常,地址是用於訪問裝置的主要地址,並列在節點的reg屬性中。我們將在本文件後面介紹reg屬性。
同級節點名稱必須是唯一的,但只要地址不同(即[email protected]和[email protected])即可,多個節點使用相同的通用名稱是正常的。有關節點命名的完整詳細資訊,請參閱ePAPR規範的第2.2.1節。
裝置:
系統中的每個裝置都由裝置樹節點表示。下一步是使用每個裝置的節點填充裝置樹檔案。現在,新節點將保持為空,直到我們可以討論如何處理地址範圍和irq。
/dts-v1/;
/{
compatible = "acme,coyotes-revenge";
cpus {
[email protected] {
compatible = "arm,cortex-a9";
};
[email protected] {
compatible = "arm,cortex-a9";
};
};
[email protected] {
compatible = "arm,pl011";
};
[email protected] {
compatible = "arm,pl011";
};
[email protected] {
compatible = "arm,pl061";
};
[email protected] {
compatible = "arm,pl190";
};
[email protected] {
compatible = "arm,pl022";
};
external-bus {
[email protected],0 {
compatible = "smc,smc91c111";
};
[email protected],0 {
compatible = "acme,a1234-i2c-bus";
[email protected] {
compatible = "maxim,ds1338";
};
};
[email protected],0 {
compatible = "samsung,k8f1315ebm", "cfi-flash";
};
};
};
在此樹中,已為系統中的每個裝置添加了一個節點,層次結構反映了裝置連線到系統的方式。即,外部總線上的裝置是外部匯流排節點的子裝置,i2c裝置是i2c匯流排控制器節點的子裝置。通常,層次結構從CPU的角度表示系統的檢視。
此樹在此時無效。它缺少有關裝置之間連線的資訊。該資料將在稍後新增。在這棵樹中要注意的一些事情:
每個裝置節點都有一個compatible屬性。 flash節點在相容屬性中有2個字串。請繼續閱讀下一節以瞭解原因。 如前所述,節點名稱反映了裝置的型別,而不是特定的模型。有關應儘可能使用的已定義通用節點名稱列表,請參閱ePAPR規範的第2.2.2節。
compatible屬性詳解:
樹中表示裝置的每個節點都需要具有該compatible屬性。compatible是作業系統用來決定繫結裝置和裝置驅動程式的關鍵。
compatible是一個字串列表。列表中的第一個字串指定節點表示的確切裝置"<manufacturer>,<model>"。以下字串表示裝置相容的其他裝置。
例如,飛思卡爾MPC8349片上系統(SoC)具有序列器件,該器件實現了National Semiconductor ns16550暫存器介面。因此,MPC8349序列裝置的相容屬性應為:compatible = "fsl,mpc8349-uart", "ns16550"。在這種情況下,fsl,mpc8349-uart指定確切的器件,並使用ns16550宣告它與National Semiconductor 16550 UART暫存器級相容。
注意:ns16550由於歷史原因,沒有製造商字首。所有新的相容值都應使用製造商字首。
這種做法允許將現有裝置驅動程式繫結到較新的裝置,同時仍然唯一地標識確切的硬體。
地址是如何工作的:
可定址的裝置使用以下屬性將地址資訊編碼到裝置樹中: reg #address-cells #size-cells
每個可定址的裝置獲取一個reg表格中的地址reg = <address1 length1 [address2 length2] [address3 length3] ...>。每個cell表示裝置使用的地址範圍。每個地址值是一個或多個稱為單元的32位整數的列表。類似地,長度值可以是單元格列表也可以是空的。
由於地址和長度欄位都是可變大小的變數,因此父節點中的#address-cells和#size-cells屬性用於表示每個欄位中有多少個單元格。或者換句話說,正確解釋reg屬性需要父節點的#address-cells和#size-cells值。要了解這一切是如何工作的,我們可以從CPU開始,將地址屬性新增到示例裝置樹中。
CPU地址:
在討論地址時,CPU節點代表了最簡單的情況。為每個CPU分配一個唯一的ID,並且沒有與CPU ID相關聯的大小。
cpus {
#address-cells = <1>;
#size-cells = <0>;
[email protected]{
compatible =“arm,cortex-a9”;
reg = <0>;
};
[email protected]{
compatible =“arm,cortex-a9”;
reg = <1>;
};
};
在cpus節點中,#address-cells設定為1,並#size-cells設定為0。這意味著子reg值是單個uint32,表示沒有大小欄位。在這種情況下,兩個cpus被分配地址0和1;#size-cells對於cpu節點是0,因為每個cpu僅被分配一個地址。
您還會注意到該reg值與節點名稱中的值匹配。按照慣例,如果節點具有reg屬性,則節點名稱必須包含unit-address,這是reg屬性中的第一個地址值。
記憶體對映裝置:
不是像在cpu節點中找到的單個地址值,而是為記憶體對映裝置分配一系列將響應的地址。#size-cells用於表示每個子reg元組中長度欄位的大小。在以下示例中,每個地址值為1個單元(32位),每個長度值也為1個單元,這在32位系統上是典型的。對於#address-cells和#size-cells,64位機器可以使用值2來獲得裝置樹中的64位定址。
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <1>;
...
[email protected] {
compatible = "arm,pl011";
reg = <0x101f0000 0x1000 >;
};
[email protected] {
compatible = "arm,pl011";
reg = <0x101f2000 0x1000 >;
};
[email protected] {
compatible = "arm,pl061";
reg = <0x101f3000 0x1000
0x101f4000 0x0010>;
};
[email protected] {
compatible = "arm,pl190";
reg = <0x10140000 0x1000 >;
};
[email protected] {
compatible = "arm,pl022";
reg = <0x10115000 0x1000 >;
};
...
};
為每個裝置分配一個基址,併為其分配區域的大小。本例中的GPIO裝置地址分配了兩個地址範圍; 0x101f3000 ... 0x101f3fff和0x101f4000..0x101f400f。
一些裝置存在於具有不同定址方案的總線上。例如,可以使用分立的晶片選擇線將器件連線到外部匯流排。由於每個父節點為其子節點定義定址域,因此可以選擇地址對映以最好地描述系統。下面的程式碼顯示了連線到外部匯流排的裝置的地址分配,晶片選擇號編碼到地址中。
external-bus {
#address-cells = <2>;
#size-cells = <1>;
[email protected],0 {
compatible = "smc,smc91c111";
reg = <0 0 0x1000>;
};
[email protected],0 {
compatible = "acme,a1234-i2c-bus";
reg = <1 0 0x1000>;
[email protected] {
compatible = "maxim,ds1338";
};
};
[email protected],0 {
compatible = "samsung,k8f1315ebm", "cfi-flash";
reg = <2 0 0x4000000>;
};
};
external-bus用2個cell表示地址值;一個用於晶片選擇號,一個用於從晶片選擇的基極偏移。長度欄位保持為單個單元格,因為只有地址的偏移部分需要具有範圍。因此,在這個例子中,每個reg條目包含3個單元格;chipselect號碼,偏移量和長度。
由於地址域包含在節點及其子節點中,因此父節點可以自由定義對匯流排有意義的任何定址方案。直接父節點和子節點之外的節點通常不必關心本地定址域,並且必須對映地址以從一個域到另一個域。
非記憶體對映裝置:
其他裝置未在處理器總線上對映記憶體地址範圍。它們可以具有地址範圍,但CPU無法直接訪問它們。相反,父裝置的驅動程式將代表CPU執行間接訪問。以i2c裝置為例,每個裝置都分配了一個地址,但沒有與之關聯的長度或範圍。這看起來與CPU地址分配大致相同。
[email protected],0 {
compatible = "acme,a1234-i2c-bus";
#address-cells = <1>;
#size-cells = <0>;
reg = <1 0 0x1000>;
[email protected] {
compatible = "maxim,ds1338";
reg = <58>;
};
};