設備樹那些事

一 概述

設備樹(Device tree)是一套用來描述硬件屬相的規則。ARM Linux採用設備樹機制源於2011年3月份Linux創始人Linus Torvalds發的一封郵件,在這封郵件中他提倡ARM平臺應該參考其他平臺如PowerPC的設備樹機制描述硬件。因爲在此之前,ARM平臺還是採用舊的機制,在kernel/arch/arm/plat-xxx目錄和kernel/arch/arm/mach-xxx目錄下用代碼描述硬件,如註冊platform設備,聲明設備的resource等。因爲這些代碼都是用來描述芯片平臺及板級差異的,所以對於內核來講都是垃圾代碼。因爲嵌入式平臺中很多公司的芯片採用的都是ARM架構,隨着Android的成功,這些代碼越來越多。據說常見的平臺如s3c2410板級目錄下邊的代碼有數萬行,難怪Linux Torvalds會說“this whole ARM thing is a fucking pain in the ass”。

內核中關於設備樹的文檔位於kernel/Documentation/devicetree/目錄。設備樹是Power.org組織定義的一套規範,規範文檔可以在官網上找到,目前最新的版本是https://www.power.org/documentation/epapr-version-1-1/。內核中設備樹相關的函數都是以of開頭的,我推測原因是設備樹機制是源於IEEE 1275 Open Firmware standard規範的,相關的代碼都是繼承下來的。如果想快速瞭解下設備樹怎麼用,可以參考http://devicetree.org/Device_Tree_Usage。

設備樹是從軟件使用的角度描述硬件的,不是從硬件設計的角度描述的。我們在寫設備樹時沒有必要按照硬件邏輯生搬硬套,也不要指望通過閱讀設備樹弄清楚硬件是如何設計的。對於軟件可以自動識別的硬件,如USB設備,PCI設備,也是沒有必要通過設備樹描述的。

我個人覺得規範內容是可以分爲兩個層次的。第一層是關於設備樹組織形式的,如設備樹結構,節點名字的構成等,第一個層次是基礎,是理解第二個層次的前提。第二層是關於設備樹內容的,如多核CPU怎樣描述,一個具體的設備如何描述。第二層可以看成是第一層的具體應用。相對來說第二層內容更多,更具體,根據描述的內容不同,定義規範的方式也有差別,比如關於CPU,內存,中斷這些基礎的內容,是在epapr中說明的,而關於外設的規範是在專門的地方說明的。

DTS(Device tree syntax,另一種說法是Device tree source)是設備樹源文件,爲了方便閱讀及修改,採用文本格式。DTC(Device tree compiler)是一個小工具,負責將DTS轉換成DTB(Device tree blob)。DTB是DTS的二進制形式,供機器使用。使用中,我們首先根據硬件修改DTS文件,然後在編譯的時候通過DTC工具將DTS文件轉換成DTB文件,然後將DTB文件燒寫到機器上(如emmc,磁盤等存儲介質)。系統啓動時,fastboot(或者類似的啓動程序,如Uboot)在啓動內核前將DTB文件讀到內存中,跳轉到內核執行的同時將DTB起始地址傳給內核。內核通過起始地址就可以根據DTB的結構解析整個設備樹。說設備樹的規範可以分成兩個層次,是針對DTS的,關於DTB的結構不在此範圍內。DTB僅僅是爲了方便機器使用而對DTS的轉換而已(也可以說DTS僅是爲了方便人類使用而對DTB的一種描述)。

設備樹首先是一個樹形結構,並且是一棵樹。除了根節點外其他子節點都有唯一的父節點,節點下可以有子節點和屬性(子節點可以看成是樹枝,屬性可以看成是葉子)。屬性由名字和值組成(名字是必須的,但是值不是必須的,如果只要根據是否存在這個屬性就可以表示我們想要的功能,那麼可以不需要有值)。

下邊是我們從內核代碼中截取的一個DTS片段。“/”表示根節點。“model = "Newflow AM335x NanoBone"”是根節點下邊的屬性。“cpus”是根節點的一個子節點。“cpu0-supply = <&dcdc2_reg>”是“cpu@0”子節點下的屬性。節點下的屬性用來表示節點的特性,子節點和父節點具有一定的從屬關係。真實的硬件不可能是這樣規則的樹形結構,所以設備樹僅是軟件開發人員爲了描述硬件而做的一個近似表示而已,連抽象都算不上。

/ {
    model = "Newflow AM335x NanoBone";
    compatible = "ti,am33xx";

    cpus {
        cpu@0 {
            cpu0-supply = <&dcdc2_reg>;
        };
    };

    memory {
        device_type = "memory";
        reg = <0x80000000 0x10000000>; /* 256 MB */
    };

    leds {
        compatible = "gpio-leds";

        led@0 {
            label = "nanobone:green:usr1";
            gpios = <&gpio1 5 0>;
            default-state = "off";
        };
    };
};
發佈了64 篇原創文章 · 獲贊 58 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章