第一步就是要為這個模型機構建一個基本結構,這是一個有效的設備樹最基本的結構。在這個階段你需要唯一的標識該機器。
/{
compatible= " Marvell ,armada38x"
};compatible 指定了系統的名稱。它包含了一個“<制造商>,<型號>”形式的字符串。重要的是要指定一個確切的設備,並且包括制造商的名子,以避免命名空間沖突。由於操作系統會使用 compatible 的值來決定如何在機器上運行,所以正確的設置這個屬性變得非常重要。
接下來就應該描述每個 CPU 了。先添加一個名為“cpus”的容器節點,然后為每個 CPU 分別添加子節點。具體到我們的情況是一個 ARM 的 雙核 Cortex A9 系統
/{
compatible= " Marvell ,armada38x";
cpus{
cpu@0{
compatible = "arm,cortex-a9";
};
cpu@1{
compatible = "arm,cortex-a9";
};
};
};每個 cpu 節點的 compatible 屬性是一個“<制造商>,<型號>”形式的字符串,並指定了確切的 cpu,就像頂層的 compatible 屬性一樣
節點名稱:現在應該花點時間來討論命名約定了。每個節點必須有一個“<名稱>[@<設備地址>]”形式的名字。
1).名稱> 就是一個不超過31位的簡單 ascii 字符串。通常,節點的命名應該根據它所體現的是什么樣的設備。比如一個 3com 以太網適配器的節點就應該命名為 ethernet,而不應該是 3com509。
2).如果該節點描述的設備有一個地址的話就還應該加上設備地址(unit-address)。通常,設備地址就是用來訪問該設備的主地址,並且該地址也在節點的 reg 屬性中列出
3).同級節點命名必須是唯一的,但只要地址不同,多個節點也可以使用一樣的通用名稱(例如 serial@101f1000 和 serial@101f2000)
設備:系統中每個設備都表示為一個設備樹節點。所以接下來就應該為這個設備樹填充設備節點。現在,知道我們討論如何進行尋址和中斷請求如何處理之前這些新節點將一直為空。
/ {
compatible = "acme,coyotes-revenge";
cpus {
cpu@0 {
compatible = "arm,cortex-a9";
};
cpu@1 {
compatible = "arm,cortex-a9";
};
};
serial@101F0000 {
compatible = "arm,pl011";
};
serial@101F2000 {
compatible = "arm,pl011";
};
gpio@101F3000 {
compatible = "arm,pl061";
};
interrupt-controller@10140000 {
compatible = "arm,pl190";
};
spi@10115000 {
compatible = "arm,pl022";
};
external-bus {
ethernet@0,0 {
compatible = "smc,smc91c111";
};
i2c@1,0 {
compatible = "acme,a1234-i2c-bus";
rtc@58 {
compatible = "maxim,ds1338";
};
};
flash@2,0 {
compatible = "samsung,k8f1315ebm", "cfi-flash";
};
};
};在此樹中,已經為系統中的每個設備添加了節點,而且這個·層次結構也反映了設備與系統的連接方式。例如,外部總線上的設備就是外部總線節點的子節點,i2c 設備就是 i2c 總線節點的子節點。通常,這個層次結構表現的是 CPU 視角的系統視圖。現在這棵樹還是無效的,因為它缺少關於設備之間互聯的信息。稍后將添加這些信息。
在這顆樹中,應該注意這些事情:
每個設備節點都擁有一個 compatible 屬性,
閃存(flash)節點的 compatible 屬性由兩個字符串構成。欲知為何,請閱讀下一節
理解 compatible 屬性:
1).樹中每個表示一個設備的節點都需要一個 compatible 屬性。compatible 屬性是操作系統用來決定使用哪個設備驅動來綁定到一個設備上的關鍵因素。
2).compatible 是一個字符串列表,之中第一個字符串指定了這個節點所表示的確切的設備,該字符串的格式為:"<制造商>,<型號>"。剩下的字符串的則表示其它與之相兼容的設備。
3).Freescale MPC8349 片上系統(SoC)擁有一個實現了美國國家半導體 ns16550 的寄存器接口的串行設備,那么 MPC8349 的串行設備的 compatible 屬性就應該是:compatible = "fsl,mpc8349-uart", "ns16550"。在這里,mpc8349-uart 指定了確切的設備,而 ns16550 則說明這是與美國國家半導體 ns16550 UART 的寄存器級兼容
4).不要使用帶通配符的 compatible 值,比如“fsl,mpc83xx-uart”或類似情況。芯片提供商無不會做出一些能夠輕易打破你通配符猜想的變化,這時候在修改已經為時已晚了。相反,應該選擇一個特定的芯片然后是所有后續芯片都與之兼容。
如何編址:
1>可編址設備使用以下屬性將地址信息編碼進設備樹
■ reg
■ #address-cells
■ #size-cells
2>每個可編址設備都有一個元組列表的 reg,元組的形式為:reg = <地址1 長度1 [地址2 長度2] [地址3 長度3] ... >。每個元組都表示一個該設備使用的地址范圍。每個地址值是一個或多個 32 位整型數列表,稱為 cell。同樣,長度值也可以是一個 cell 列表或者為空。
3>由於地址和長度字段都是可變大小的變量,那么父節點的 #address-cells 和 #size-cells 屬性就用來聲明各個字段的 cell 的數量。換句話說,正確解釋一個 reg 屬性需要用到父節點的 #address-cells 和 #size-cells 的值。要知道這一切是如何運作的,我們將給模型機添加編址屬性,就從 CPU 開始。
CPU 編址:
CPU 節點表示了一個關於編址的最簡單的例子。每個 CPU 都分配了一個唯一的 ID,並且沒有 CPU id 相關的大小信息。
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
compatible = "arm,cortex-a9";
reg = <0>;
};
cpu@1 {
compatible = "arm,cortex-a9";
reg = <1>;
};
};在 cpu 節點中,#address-cells 設置為 1,#size-cells 設置為 0。這意味着子節點的 reg 值是一個單一的 uint32,這是一個不包含大小字段的地址,為這兩個 cpu 分配的地址是 0 和 1。cpu 節點的 #size-cells 為 0 是因為只為每個 cpu 分配一個單獨的地址。你可能還會注意到 reg 的值和節點名字是相同的。按照慣例,如果一個節點有 reg 屬性,那么該節點的名字就必須包含設備地址,這個設備地址就是 reg 屬性里第一個地址值
內存映射設備:
與 cpu 節點里單一地址值不同,應該分配給內存映射設備一個地址范圍。#size-cells 聲明每個子節點的 reg 元組中長度字段的大小。在接下來的例子中,每個地址值是 1 cell(32 位),每個長度值也是 1 cell,這是典型的 32 位系統。64 位的機器則可以使用值為 2 的 #address-cells 和 #size-cells 來獲得在設備樹中的 64 位編址。
/ {
#address-cells = <1>;
#size-cells = <1>;
...
serial@101f0000 {
compatible = "arm,pl011";
reg = <0x101f0000 0x1000 >;
};
serial@101f2000 {
compatible = "arm,pl011";
reg = <0x101f2000 0x1000 >;
};
gpio@101f3000 {
compatible = "arm,pl061";
reg = <0x101f3000 0x1000
0x101f4000 0x0010>;
};
interrupt-controller@10140000 {
compatible = "arm,pl190";
reg = <0x10140000 0x1000 >;
};
spi@10115000 {
compatible = "arm,pl022";
reg = <0x10115000 0x1000 >;
};
...
};每個設備都被分配了一個基址以及該區域的大小。這個例子中為 GPIO 分配了兩個地址范圍:0x101f3000...0x101f3fff 和 0x101f4000..0x101f400f。
一些掛在總線上的設備有不同的編址方案。例如一個帶獨立片選線的設備也可以連接至外部總線。由於父節點會為其子節點定義地址域,所以可以選擇不同的地址映射來最恰當的描述該系統。下面的代碼展示了設備連接至外部總線並將其片選號編碼進地址的地址分配
external-bus {
#address-cells = <2>
#size-cells = <1>;
ethernet@0,0 {
compatible = "smc,smc91c111";
reg = <0 0 0x1000>;
};
i2c@1,0 {
compatible = "acme,a1234-i2c-bus";
reg = <1 0 0x1000>;
rtc@58 {
compatible = "maxim,ds1338";
};
};
flash@2,0 {
compatible = "samsung,k8f1315ebm", "cfi-flash";
reg = <2 0 0x4000000>;
};
};外部總線的地址值使用了兩個 cell,一個用於片選號;另一個則用於片選基址的偏移量。而長度字段則還是單個 cell,這是因為只有地址的偏移部分才需要一個范圍量。所以,在這個例子中,每個 reg 項都有三個 cell:片選號、偏移量和長度。
由於地址域是包含於一個節點及其子節點的,所以父節點可以自由的定義任何對於該總線來說有意義的編址方案。那些在直接父節點和子節點以外的節點通常不關心本地地址域,而地址應該從一個域映射到另一個域
chosen 節點:
chosen 節點並不代表一個真正的設備,只是作為一個為固件和操作系統之間傳遞數據的地方,比如引導參數。chosen 節點里的數據也不代表硬件。通常,chosen 節點在 .dts 源文件中為空,並在啟動時填充。
chosen {
bootargs = "root=/dev/nfs rw nfsroot=192.168.1.1 console=ttyS0,115200";
};
...................
....................