目錄

1.什麼是設備樹?

2.設備樹的結構

3.節點結構

4.節點標準屬性

4.1 compatible

4.2 status

4.3 #address-cells #size-cells

4.4 reg

4.5 name

4.6 device_type

4.7 phandle

4.8 virtul-reg

4.9 range

4.10 dma-range

5.特殊節點

5.1 /aliases node

5.2 /chosen node

6."of_"相關函數

6.1 查找節點

6.1.1 of_find_node_by_name

6.1.2 of_find_node_by_type

6.1.3 of_find_compatible_node

6.1.4 of_find_node_by_path

6.2 提取屬性值

6.2.1 of_find_property

 6.2.2 of_property_read_u32_index

 6.2.3 of_property_read_u*_array

6.2.4 of_property_read_u*


 

        設備樹被引入的背景就不説了。直接來看設備樹。

1.什麼是設備樹?

        設備樹是用一種樹狀的結構和節點,來描述系統中的硬件。每個節點都具有描述被表示的設備的特性的屬性/值等。那麼有幾個概念。

DTS

設備樹的代碼源文件,可以理解為各開發板,對DTSI各節點的引用定製。

DTSI

同平台更通用的設備樹代碼,可以作為頭文件定義在DTS文件中。

DTC

DTS編譯文件,可以編譯DTS為DTB,也可以將DTB反編譯為DTS

DTB

DTC編譯出來的二進制文件

2.設備樹的結構

/dts-v1/;                   
[memory reservations]        
/{
    [property defintions]
    [child node]
};

/dts-v1/;

設備樹的版本信息

[memory reservations] 

預留的內存空間不被內存使用/分配:/memreserve/<address><lenth>;

[property defintions]

屬性的name和屬性的value:property-name = value;

property-name有兩種,一種是用户定義的名字如“led-pins”,一種是固定的名字如“compatible”。

value的取值如下:

empty

可以為空如:enable-active-high;

<u32>

32位數據:tx_delay = <0x30>;

<u64>

兩個32位數據:<0x11223344 0x55667788>.

<string>

字符串:compatible = "silergy,syr827";

<prop-encoded-array>

規定值:status = "okay";

<phandle>

phandle值:基本不推薦使用了

<stringlist>

多個字符串:“hello”,”world”

十六進制數

local-mac-address = [00 00 12 34 56 78];



or:local-mac-address = [000012345678];

節點的引用

interrupt-parent = < &mpic >;



or:interrupt-parent = < &{/soc/interrupt-controller@40000} >;

沒有<>的節點引用

ethernet0 = &EMAC0; 這裏&EMAC0會被展開為節點的全路徑

3.節點結構

        設備樹只有一個根節點'/',和若干個節點node1,node2....如果這些節點下還有節點如node1下有節點node-a,那麼node-a稱之為子節點,node1為它的父節點。

[label:] node-name[@unit-address] {
[properties definitions]
[child nodes]
};

[label:]

節點的標識,方便引用

node-name

節點的名字

[@unit-address]

節點內存的起始地址(如果沒有相同名字節點需要區分,可省略)

4.節點標準屬性

4.1 compatible

        該節點用於匹配platform Driver,當該屬性的名字和platform_drvier中的of_match_table匹配時,則驅動匹配上,會執行probe函數。

例: compatible = "active-semi,act8846";

4.2 status

        節點的狀態,可用、禁用等,有錯誤等。

value

Description

"okay"

設備可用

"disabled"

設備禁用

"fail"

設備出現了錯誤,不可用

"fail-sss"

設備出現了錯誤,錯誤內容為"sss"

例:

 status = "okay";

4.3 #address-cells #size-cells

#address-cells

指定子節點中"reg"屬性的地址是由幾個32位數表示

#size-cells

指定子節點中"reg"屬性的地址長度是由幾個32位數表示

bus_intmem@ff700000 {
                compatible = "mmio-sram";
                reg = <0x0 0xff700000 0x0 0x18000>;
                #address-cells = <1>;    //用1個32位數表示地址
                #size-cells = <1>;        //用1個32位數表示長度
                ranges = <0 0x0 0xff700000 0x18000>;
                smp-sram@0 {
                        compatible = "rockchip,rk3066-smp-sram";
                        reg = <0x00 0x10>;    //這裏就是體現
                };

4.4 reg

        用來定義地址/寄存器的起始地址和長度,裏面的值由#address-cells #size-cells來指定。

格式:reg = <addr1 lenth1 addr2 lenth2 ...>

4.5 name

        不建議使用

4.6 device_type

        不建議使用,應該只包含在"cpu"和"memeroy"節點上,但是有些設備也會用該屬性去描述,不知道為什麼

serial@4600 {
    device_type = "serial";
    compatible = "ns16550";
    reg = <0x4600 0x100>;
    clock-frequency = <0>;
    interrupts = <0xA 0x8>;
    interrupt-parent = <&ipic>;
}

4.7 phandle

        用來指定該節點是設備樹中唯一的節點,可以被其他節點來使用,進而關聯該節點,現在一般不用了。

pic@10000000 {
    phandle = <1>;
    interrupt-controller;
};

another-device-node {
    interrupt-parent = <1>;
};

4.8 virtul-reg

        沒研究

4.9 range

        沒研究

4.10 dma-range

        沒研究

5.特殊節點

5.1 /aliases node

        官方的解釋為該節點在根節點下,可以為其他節點定義一個別名。先來看個例子。

/ {
        compatible = "rockchip,rk3288";

        interrupt-parent = <&gic>;

        aliases {
                ethernet0 = &gmac;
                i2c0 = &i2c0;
                i2c1 = &i2c1;
                i2c2 = &i2c2;
                ...
                ...
        };
};

        上面有講過 property-name = value,當value沒有<>時,會被展開為完整路徑,上面可以通過反編譯看到如"&i2c0"的全路徑,下面是個例子。

aliases {
    serial0 = "/simple-bus@fe000000/serial@llc500";
    ethernet0 = "/simple-bus@fe000000/ethernet@31c000";
};

        在網上看了一些文章,內核會解析該節點,通過展開的node path找到該節點,並將別名的id(也就是I2C0,I2C1後面的數字'0','1')解釋出來,用來註冊驅動和設備。

5.2 /chosen node

        系統啓動時所選擇的參數,如nfs掛載點等等。

chosen {
    bootargs = "root=/dev/nfs rw nfsroot=192.168.1.1 console=ttyS0,115200";
};

6."of_"相關函數

6.1 查找節點

6.1.1 of_find_node_by_name

struct device_node *of_find_node_by_name(struct device_node *from, const char *name);

功能

通過節點名字查找節點

*from

開始查找的節點名字,如果'NULL'則從從根節點查找整個設備樹

*name

要查找的節點名字

返回值

查找到的節點指針

6.1.2 of_find_node_by_type

struct device_node *of_find_node_by_type(struct device_node *from, const char *type);

功能

通過 'device_type' 的值查找節點

*from

開始查找的節點名字,如果'NULL'則從從根節點查找整個設備樹

*name

要查找的 ‘device_type’屬性的value(字符串)

返回值

查找到的節點指針

6.1.3 of_find_compatible_node

struct device_node *of_find_compatible_node(struct device_node *from, const char *type, const char *compatible)

功能

通過 'device_type' 和 'compatible' 兩個屬性的值查找節點,如果device_type為NULL,則忽略這個屬性的從compatible的值查找

*from

開始查找的節點,如果為 NULL表示從根節點開始查找整個設備樹

*type

要查找的節點對應的device_type屬性值,'NULL'代表忽略這個屬性

 *compatible

要查找的節點所對應的 compatible屬性值

返回值

查找到的節點指針

6.1.4 of_find_node_by_path

struct device_node *of_find_node_by_path(const char *path)

功能

通過節點的全路徑來查找節點

*path

節點的全路徑

返回值

查找到的節點指針

6.2 提取屬性值

6.2.1 of_find_property

property *of_find_property(const struct device_node *np, const char *name, int *lenp)

功能

查找屬性

*np

節點指針

*name

屬性的名字

*lenp

屬性的value長度

返回值

查找到的節點指針

 6.2.2 of_property_read_u32_index

int of_property_read_u32_index(const struct device_node *np, const char *propname,                   
                               u32 index, u32 *out_value);

功能

讀取屬性的32位無符號的值

*np

節點指針

*propname

屬性的名字

index

屬性值的index

 *out_value

讀取到的值

返回值

0讀取成功,非0讀取失敗

opp-microvolt = <1111 2222 3333>;    //該屬性的value是3個32位無符號的整形值

如果這時候函數的index為0,那麼讀到的值為'1111'

 6.2.3 of_property_read_u*_array

int of_property_read_u8_array(const struct device_node *np,
			const char *propname, u8 *out_values, size_t sz);

int of_property_read_u16_array(const struct device_node *np,
			const char *propname, u16 *out_values, size_t sz);

int of_property_read_u32_array(const struct device_node *np,
            const char *propname,u32 *out_values, size_t sz);

int of_property_read_u64_array(const struct device_node *np,
            const char *propname,u32 *out_values, size_t sz);

功能

屬性值是多個u8(u16,u32,u64)數,可以一次性讀出來

*np

節點指針

*propname

屬性的名字

*out_values

讀取到的數組指針

 sz

要讀取的數組成員的數量

返回值

0讀取成功,非0讀取失敗

6.2.4 of_property_read_u*

int of_property_read_u8(const struct device_node *np, const char *propname, 
                        u8 *out_value)
int of_property_read_u16(const struct device_node *np, const char *propname, 
                        u16 *out_value)
int of_property_read_u32(const struct device_node *np, const char *propname, 
                        u32 *out_value)
int of_property_read_u64(const struct device_node *np, const char *propname, 
                        u64 *out_value)

功能

屬性的值只有一個u8(u16,u32,u64)的值,讀取該值

*np

節點指針

*propname

屬性的名字

*out_values

讀取到的值的指針

返回值

0讀取成功,非0讀取失敗

備註:

這些函數完全可以用_array的函數替代,只不過sz變量設置為1就行