5. 設(shè)備樹的規(guī)范 - DTS格式

一、概述

???? ARM Device Tree起源于OpenFirmware (OF),在Linux 2.6中,arch/arm/plat-xxx和arch/arm/mach-xxx中充斥著大量的垃圾代碼,相當(dāng)多數(shù)的代碼只是在描述板級(jí)細(xì)節(jié),而這些板級(jí)細(xì)節(jié)對(duì)于內(nèi)核來講,不過是垃圾,如板上的platform設(shè)備、resource、i2c_board_info、spi_board_info以及各種硬件platform_data。常見的s3c2410、s3c6410等板級(jí)目錄,代碼量在數(shù)萬行。
???? Linus Torvalds對(duì)于此種情況大發(fā)雷霆,在2011年的ARM Linux郵件列表宣稱this whole ARM thing is a f*cking pain in the ass”。
???? 所以Linux開發(fā)社區(qū)就開始整改,設(shè)備樹最早用于PowerPC等其他體系架構(gòu),ARM架構(gòu)開發(fā)社區(qū)就開始采用設(shè)備樹來描述設(shè)備的信息。

二、設(shè)備樹結(jié)構(gòu)

????? Device Tree是一種描述硬件的數(shù)據(jù)結(jié)構(gòu),由一系列被命名的結(jié)點(diǎn)(node)和屬性(property)組成,而結(jié)點(diǎn)本身可包含子結(jié)點(diǎn)。所謂屬性,其實(shí)就是成對(duì)出現(xiàn)的namevalue。在Device Tree中,可描述的信息包括(原先這些信息大多被hard code到kernel中):CPU的數(shù)量和類別,內(nèi)存基地址和大小,總線和橋,外設(shè)連接,中斷控制器和中斷使用情況,GPIO控制器和GPIO使用情況,Clock控制器和Clock使用情況。
????? 通常由.dts文件以文本方式對(duì)系統(tǒng)設(shè)備樹進(jìn)行描述,經(jīng)過Device Tree Compiler(dtc)dts文件轉(zhuǎn)換成二進(jìn)制文件binary device tree blob(dtb),.dtb文件可由Linux內(nèi)核解析,有了device tree就可以在不改動(dòng)Linux內(nèi)核的情況下,對(duì)不同的平臺(tái)實(shí)現(xiàn)無差異的支持,只需更換相應(yīng)的dts文件,即可滿足。
????? 設(shè)備樹信息被保存在一個(gè)ASCII 文本文件中,適合人類的閱讀習(xí)慣,類似于xml文件, 在ARM Linux中,一個(gè).dts文件對(duì)應(yīng)一個(gè)ARMmachine放置在內(nèi)核的arch/arm/boot/dts/目錄。

三、設(shè)備樹語法

3.1 節(jié)點(diǎn)node

3.2 屬性property

屬性擁有兩種格式:
Property格式1(沒有值) : [label:] property-name;
Property格式2(鍵值對(duì)) : [label:] property-name = value;;

四、設(shè)備樹實(shí)例

下述例子譯自: http://elinux.org/Device_Tree_Usage

下面給出一個(gè)例子,從0開始描述如何寫一個(gè)完整的設(shè)備樹?,F(xiàn)在有個(gè)arm平臺(tái)的板子,假設(shè)制造商為“acme”我們給他命名為“Coyote's Revenge”首先,假設(shè)我們有如下的硬件平臺(tái):

  • 一顆 32bit ARM CPU

  • 處理器本地總線上映射了串口SPI控制器、I2C控制器、中斷控制器以及外部總線橋。

  • 基地址為0,大小為256MB的SDRAM

  • 基地址分別為0x101F1000 和0x101F2000的2個(gè)串口

  • 基地址為0x101F3000 GPIO控制器

  • 基地址為0x10170000的SPI 控制器上有如下的設(shè)備:

  • MMC 卡槽的SS引腳連接到了GPIO #1

  • 外部總線橋上有如下的設(shè)備:

  • SMC公司生產(chǎn)的SMC91111 Ethernet,其基地址為0x10100000。

  • 在基地址為0x10160000的 i2c 控制器有如下設(shè)備:

  • 美信公司的DS1338 實(shí)時(shí)時(shí)鐘芯片. 從站相應(yīng)地址為0x58

  • 大小為64MB 的 NOR flash 其基地址為0x30000000

下面將按照上面的描述信息,寫一個(gè)DTS文件。

初始化結(jié)構(gòu)體
首先先給整個(gè)設(shè)備樹寫一個(gè)框架如下所示:

/dts-v1/;

/ {
    compatible ="acme,coyotes-revenge";
};

上面首先在根節(jié)點(diǎn)下寫了一個(gè)屬性compatible,該屬性是系統(tǒng)用來識(shí)別不同板級(jí)設(shè)備的重要依據(jù),其一般由廠商名和樣板名兩部分組成,比如在上面我們的制造商為acme板子的名字叫做coyotes-revenge。
加入CPU
假如我們的CPU是一顆雙核A9的CPU,我們添加一個(gè)叫”cpus”的子節(jié)點(diǎn),具體如下:

/dts-v1/;

/ {

    compatible ="acme,coyotes-revenge";

    cpus {
       cpu@0 {
           compatible = "arm,cortex-a9";
       };

       cpu@1 {
           compatible = "arm,cortex-a9";
       };
    };
};

cpu的compatible設(shè)置與頂層的類似,有兩部分組成。Arm描述了制造商,cortex-a9指明了型號(hào)。

系統(tǒng)中每個(gè)設(shè)備都是依靠設(shè)備樹節(jié)點(diǎn)來描述的,接下來就要添加一些設(shè)備節(jié)點(diǎn)來描述每一個(gè)設(shè)備:

/dts-v1/;

/ {

    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";

       };

    };

};

通過上面的列表可以看出來,通過dts的層次關(guān)系,可以看到具體的板級(jí)的設(shè)備連接關(guān)系,比如外部總線上有ethercat、i2c和flash三個(gè)設(shè)備。

但是上面描述的這課樹還不是一個(gè)完整有效的設(shè)備樹,因此他缺少必要的連接方式、地址信息等。稍后會(huì)加上這些信息。
理解Compatible
每個(gè)設(shè)備節(jié)點(diǎn)都會(huì)有compatible屬性, 設(shè)備與驅(qū)動(dòng)之間的結(jié)合就依賴這個(gè)屬性的匹配。

Compatible屬性是由字符串列表組成,就像上面列出的flash節(jié)點(diǎn),compatible有兩個(gè)屬性值,以一個(gè)字符串確切的表示該設(shè)備的信息,第二個(gè)字符串描述的與該節(jié)點(diǎn)描述符相兼容的設(shè)備。
設(shè)備如何尋址
設(shè)備尋址地址在設(shè)備樹中通過如下的屬性信息來表示:
reg

address-cells

size-cells

每一個(gè)可尋址設(shè)都會(huì)有一個(gè)reg屬性,該屬性有一個(gè)或多個(gè)元素組成,其基本格式為:
reg =<address1 length1 [address2 length2] [address3 length3] ... >
上面的每一個(gè)元素都代表設(shè)備的尋址地址及其尋址大小,每一個(gè)元素中的address值可以是一個(gè)或者多個(gè)無符號(hào)32位整形數(shù)據(jù)類型cell來表示,元素中的length可以為空也可以使一個(gè)或者多個(gè)無符號(hào)32位整形數(shù)據(jù)類型cell。
由于每個(gè)可尋址設(shè)備都會(huì)有reg屬性可設(shè)置,而且reg屬性元素也是靈活可選擇的,那么誰來制定reg屬性元素中每個(gè)元素也就是address和length的個(gè)數(shù)呢?
在這里,要關(guān)注到期父節(jié)點(diǎn)的兩個(gè)屬性,其中#address-cells表示reg中address元素的個(gè)數(shù),#size-cells用來表示length元素的個(gè)數(shù)。
為了展示剛剛接手實(shí)行的作用,那么現(xiàn)在做一個(gè)演示,首先從cpu節(jié)點(diǎn)開始演示:
CPU 尋址地址
對(duì)于尋址地址的編寫,cpu節(jié)點(diǎn)是最簡單的一個(gè)例子,之前介紹,而每個(gè)cpu節(jié)點(diǎn)都包含一個(gè)標(biāo)記ID,但是沒有其他的描述信息,這里填充一些其他的屬性:

 cpus {

        #address-cells= <1>;

       #size-cells = <0>;

        cpu@0 {

           compatible = "arm,cortex-a9";

            reg= <0>;

        };

        cpu@1 {

           compatible = "arm,cortex-a9";

            reg= <1>;

        };

    };

在cpus節(jié)點(diǎn) #address-cells 賦予 1, #size-cells 賦予 0.。這意味著在其子節(jié)點(diǎn)的reg只有一個(gè)地址元素值,沒有長度元素值。在這個(gè)案例當(dāng)中,兩顆cpu核的地址分別唄分配成0和1。因?yàn)槊總€(gè)cpu只分配了地址,所以節(jié)點(diǎn) #size-cells元素被設(shè)置為 0。

內(nèi)存映射設(shè)備
需要內(nèi)存映射的設(shè)備不同于上面的cpu節(jié)點(diǎn),這類的設(shè)備需要一段內(nèi)存而不是單一的內(nèi)存地址,因此不近需要包含內(nèi)存的基地址還而且還需要映射地址的長度,因此需要使用 #size-cells屬性來表示reg屬性元素中表示地址長度元素的個(gè)數(shù)。在下面的例子中,每一個(gè)節(jié)點(diǎn)的address值有一個(gè)32位無符號(hào)整形數(shù)據(jù)而且length值也是用一個(gè)32位無符號(hào)整形數(shù)據(jù)來表示。因此在32的系統(tǒng)中 #address-cells 和#size-cells都要設(shè)置為1,但是在64位系統(tǒng)中 #address-cells就要設(shè)置成2了。具體設(shè)置如下:

/dts-v1/;
/ {

    #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 >;
    };
    ...

上面的例子中reg屬性都有address元素和length屬性,值的注意的是,例子中的GPIO被分配了兩個(gè)地址范圍,分別是 0x101f3000...0x101f3fff 以及0x101f4000..0x101f400f。

有一些設(shè)備可能有不同的尋址方案,比如一個(gè)設(shè)備掛載到總線上連接一個(gè)片選信號(hào)線,可以通過片選信號(hào)選擇不同的設(shè)備。由于父節(jié)點(diǎn)可以定義了其子節(jié)點(diǎn)的地址映射域,所以可以選擇最適合的一項(xiàng)來描述硬件設(shè)備。下面的代碼就是把片選號(hào)碼編入地址碼掛載到外部總線上的一個(gè)設(shè)備。

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";
            compatible= <2 0 0x4000000>;

        };

    };

上面的代碼中, #address-cells 屬性為2,則表示reg屬性的address有兩個(gè)地址域,其中一個(gè)表示片選號(hào),另一個(gè)表示設(shè)備到片選基地址的偏移量,#size-cells為1,其地址范圍量的個(gè)數(shù)還是一個(gè)32位的無符號(hào)整數(shù)。所以最后reg有三個(gè)屬性值,分別表示片選號(hào)、偏移量、地址范圍。

無內(nèi)存映射設(shè)備
其他的一些設(shè)備,他們?cè)谔幚砥骺偩€瓶沒有內(nèi)存映射。他們擁有地址范圍但是他們不被cpu直接的訪問,而是被父設(shè)備驅(qū)動(dòng)替代cpu進(jìn)行訪問。

舉個(gè)例子,對(duì)于i2c設(shè)備,每個(gè)設(shè)備都會(huì)有一個(gè)指定的訪問地址,但是這些設(shè)備不會(huì)有相關(guān)聯(lián)的范圍或者地址長度,這有點(diǎn)類似cpu節(jié)點(diǎn)地址分配。如下是具體代碼的例子:

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



參考:
https://blog.csdn.net/sgmenghuo/article/details/45071615
https://blog.csdn.net/woshidahuaidan2011/article/details/52948732
設(shè)備樹使用文檔

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容