1. 程式人生 > >淺析Linux Device Tree

淺析Linux Device Tree

DeviceTree基礎

DeviceTree(以下簡稱DT)用於描述裝置資訊以及裝置於匯流排之間的層級關係,DT可用於描述絕大多數板級裝置的細節,包括CPU、記憶體、中斷、匯流排以及外設等,與DT相關的Object有dts、dtsi、dtc、dtb、dt.img。

  • dts:DT原始檔稱為dts檔案,Ascii文字檔案,一般一個dts檔案對應一個Machine,ARM架構下dts檔案存放於arch/arm/boot/dts/目錄下
  • dtsi:多個Machine/SoC公用的dt檔案,i代表include
  • dtc:DeviceTree Compile,用於將dts檔案編譯成二進位制dtb檔案
  • dtb:DeviceTree Bolb,由dtc編譯dts檔案生成的二進位制目標檔案
  • dt.img:多個dtb檔案打包形成dt.img,以適配多個Machine,dts/dtb的結構是標準化的,dt.img有頭資訊和多個dtb組成,因為沒有統一的標準,不同的廠商頭資訊可能是不同的

目前Android廠商大都使用kernel + ramdisk.img + dt.img的方式打包成boot.img。

本章將詳細介紹如下內容:

  • devicetree檔案結構
  • devicetree語法基礎
  • devicetree檔案結構例項解析
  • device tree compile用法介紹

DTS檔案結構

DTS檔案主要由:root-node、child-node、property、include組成

  • root-node: 由’/’表示,DT的Entry Point,所有裝置均以子節點的形式處於根節點下
  • child-node: node的形式為 node-name {};{}中是該node的實際內容,根節點下一般是Platform裝置和匯流排,外設以子節點形式存在於匯流排類的節點中。如下的示例中,cpus 這個節點位於根節點下,代表著所有cpu,cpu0~x以子節點形式處於cpus下,代表著SoC上所有的cpu
  • property: 屬性,以key-value的形式表示,位於節點中
  • include file: 用於包含其他原始檔到dts中,dtsi一般中多個Machine公用的檔案(i代表include),h檔案在dts中一般用於巨集定義
 /include/ "skeleton.dtsi"
 /include/ <dt-bindings/clock/msm-clocks-a7.h>
/ {
        model = "Qualcomm Technologies, Inc. MSM 8226";
        compatible = "qcom,msm8226";
        interrupt-parent = <&intc>;

        cpus {
                #size-cells = <0>;
                #address-cells = <1>;

                CPU0: [email protected]0 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a7";
                        reg = <0x0>;
                };

注:
1. 並非所有node都代表實際的裝置,例如上例中的cpus。
2. node通常還可以用來表示Runtime Configuration,例如bootargs,boot address

DT語法基礎

這一節將介紹兩個概念:Property,Label and Reference。

Property

屬性(Property)是DT中描述裝置的原語,其形式為:

          Key = Value;

Key的種類有很多種,但通常可以大致分為:dt保留的key,例如compatible/#address-cell/reg等;以及廠商自定義的key,例如goodix,irq-gpio等。需要明確的是,並非IEEE或者Linux定義了key的種類,key種類由解析devicetree的程式碼決定,之所以說compatible/reg這些屬性是保留的是因為核心中這些key已經約定俗成了。

按key可以表述的資料型別,可以分為:

  • 字串:string-prop = “a string”;
  • 字串列表:string-list = “hi”,”str”,”list”;
  • 整型資料:cell-prop = <0xaa>;
  • 二進位制資料:binary-prop = [aa bb f8];
  • 混合資料:mixed-prop = “str”,<0x123>,[ff dd];
  • 布林型別:bool-porp;
  • 引用型別:ref-prop = <&other-node>

可以看到,devicetree中使用不同的符號包裹資料來表示不同的資料型別;上述資料型別中的key只是為了表達意思,並非linux devicetree中使用的key;布林型別的Property只有key沒有value,例如定義了bool-prop這代表這個屬性為true,若沒定義則代表該屬性為false

常見的Key及意義

Key 型別 釋義
compatible string 用於device與driver匹配
reg integer 表示裝置的地址空間
address-cells integer 設定子節點reg屬性中地址資料的cell數
size-cells integer 設定子節點reg屬性中地址長度的cell數
interrupt-parent reference 指定該裝置的中斷連線到的int controller

上表中知識簡單羅列了最常用的Key,實際Machine的dts中包含眾多的Key,並且絕大多數Key是由SoC廠商或者外設廠商自定義的。有關這些Key的意義以及寫法介紹,核心要求廠商在Documents/devicetree/bindings/目錄下提供文件介紹,如果大家在閱讀或編寫dts檔案時遇到問題,應該首先到bindings目錄下查閱對應的介紹文件。

有關屬性中Key的命名原則有一個約定俗成的做法:SoC廠商或其他外設廠商應使用 vendor,prop的形式。屬性Compatible也應遵守”vendor,model”的形式。
例如qcom,qcom,clk-rates;goodix,irq-gpio

Labels and Reference

標籤和引用是為了方便編寫dts檔案,當標籤用於節點時開發人員可在任意地方引用該標籤而不用關注該標籤的全路徑;當標籤應用於屬性時,開發人員可以在其他屬性中引用該標籤,避免重複的工作。例如Label一個字串,避免在每個需要的地方重複寫同一個字串。

全路徑在dts中即節點的在樹形結構中的位置,即從根節點索引到該節點所經過的所有父節點組合

Lable的方法很簡單,請看如下例子

Label
  i2c0: i2c@ff121288 {};
  msmgpio: gpio@fd510000 {
      msmgpio-comp: compatible = "msm-gpio";
  };

Reference
/*goodix-ts is a i2c touch device */
  &i2c0 {
    goodix-ts@5d { 
        goodix,rst-gpio = <&msmgpio 16 0x00>;
    }
  }

 Without Reference
 / {
   i2c@ff121288 {
      goodix-ts@5d { 
          goodix,rst-gpio = <&msmgpio 16 0x00>;
      }
   };
 };

上例中i2c0, msmgpio, msmgpio-comp均是Label,我們在描述goodix-ts裝置的時候引用了標籤。 假設goodix-ts掛載在i2c0上,不必像Without Reference下的示例一樣完整書寫i2c0的全路徑,而只需引用前面定義的i2c0這個標籤即可。屬性goodix,rst-gpio中引用到了msmgpio,這是比較常見的設定gpio pin的方法。對比使用標籤引用和不使用標籤引用的寫法我們就能感受到標籤與引用的妙處了。

另外,也可以使用alias為標籤定義別名,如:alias { i2c_0 = &i2c0};,這樣在引用的地方就不用再寫&號了,alias+label+reference是非常常用的做法。

Linux DTS檔案結構解析

本節將以Qcom的dts檔案為例,介紹dts檔案的結構、dts如何與一個Machine對應。

核心版本:MSM Kernel3.10

Branch: android-msm-angler-3.10-marshmallow-dr

Qcom的dts檔案位於arch/arm/boot/dts/qcom/,arm64平臺的dts軟連結到前面的目錄下,因此arm/arm64平臺的dts均存放於前面的目錄下。以Qcom MSM8974平臺為例,其對應的dts檔案有

msm8974-v1-fluid.dts
msm8974-v1-liquid.dts
msm8974-v1-mtp.dts
msm8974-xx-xxx.dts

這裡僅羅列幾個dts檔案,由於平臺版本的不同,存在不同的dts。那Build核心的時候是如何決定哪些dts需要被編譯呢? 答案在arch/arm/boot/dts/qcom/Makefile中,

ifeq ($(CONFIG_OF),y)
#include $(srctree)/arch/arm/boot/dts/qcom/Makefile.board
dtb-$(CONFIG_ARCH_MSM8974) += msm8974-v1-cdp.dtb \
    msm8974-v1-fluid.dtb \
    msm8974-v1-liquid.dtb \
    msm8974-v1-mtp.dtb \
    msm8974-v1-rumi.dtb \
    msm8974-v1-sim.dtb \

以上截取了Makefile的一部分,Build Kernel時將根據實際Platform型別決定哪些dts檔案將被包含到dtb target中,本例中平臺為MSM8974,包含了數個dts檔案。最終多個dtb檔案打包成dt.img,dt.img與Kernel,Ramdisk一起打包生成boot.img。Bootloader啟動時從SoC暫存器中讀取id資訊, 從dt.img中找到對應的dtb並裝載到RAM中然後傳遞地址給Kernel,匹配的屬性即:dtb根節點下的compatible、qcom,msm-id屬性。

一個具體的dts檔案通常包含多個dtsi檔案,大致分為以下幾類
1. 骨架類dtis - skeleton.dtsi,skeleton64.dtsi
2. pinctrl dtsi - msm8974-pinctrl.dtsi,定義Pin Mux
3. regulator dtsi - msm8974-regulator.dtsi,定義電源
4. clock dtsi - msm8974-clock.dtsi,定義時鐘訊號
5. panel/camera/sensor dtsi - msm8974-mdss-panel.dtsi,msm8974-camera-sensor-xxx.dtsi
6. gpu/ion/leds/xxx

dtsi型別比較多,這裡進列出部分。

Skeleton DTSI

Skeleton的作用是定義裝置啟動所需要的最小的元件,它定義了root-node下的最基本且必要的child-node型別,通常對應SoC上的基礎設施如CPU,Memory等。

/*
 * Skeleton device tree in the 64 bits version; the bare minimum
 * needed to boot; just include and add a compatible value.  The
 * bootloader will typically populate the memory node.
 */
/ {
    #address-cells = <2>;
    #size-cells = <2>;
    cpus { };
    soc { };
    chosen { };
    aliases { };
    memory { device_type = "memory"; reg = <0 0 0 0>; };
};

如上Code來源於skeleton64.dtsi,在root-node下一共定義了5個基本的child-node,cpus代表SoC上所有的cpu,具體cpu的個數以及引數定義在cpus的child-node下;soc代表平臺上的所有片上外設以及片外外設,例如uart/clock/spi/i2c/display/…具體這些外設的定義在其他dts/dtsi檔案中;chosen用於定義runtime configuration;aliases用於定義node的別名;memory用於定義裝置上的實體記憶體。

address-cells定義了根節點的所有子節點的地址空間屬性(reg屬性)中使用2個cell來表示啟示地址

size-cells定義了根節點的所有子節點的地址空間屬性(reg屬性)中使用2個cell來表示地址空間的長度

Main-DTS File

Main dts file將各種功能的dtsi檔案組合,形成一個功能完善的Machine(SoC+Periph),以msm8974-v1-fluid.dts為例

/dts-v1/;      //定義了dts的版本
#include "msm8974-v1.dtsi"  // 各種裝置的定義分散到獨立的dtsi中
#include "msm8974-fluid.dtsi"
/ {
    model = "Qualcomm Technologies, Inc. MSM 8974 FLUID";
    compatible = "qcom,msm8974-fluid", "qcom,msm8974", "qcom,fluid";
    qcom,msm-id = <126 3 0>,
              <185 3 0>,
              <186 3 0>;
};
&pm8941_chg {
    qcom,charging-disabled;
};

細心的同學可能看到了有些屬性直接定義在root-node下,這部分屬性用於定義Platform的ID資訊,compatible屬性定義匹配的平臺型別,qcom,msm-id是SoC廠商定義的Key,這個屬性定義匹配的SoC,Kernel啟動時會從SoC的暫存器中讀取id與之比對。

DTS中&用於引用已經定義的node,假設要在8974-v1-fluid.dts中定義個i2c adpater,則應該這樣寫

&soc {
    // i2c adapter屬於SoC上的裝置,因此定義在soc節點下
    i2c@0xff188888 {
         // node content
    }
    i2c@0xff399999 {
         // node content
    }
};

這裡又出現了一個符號@,@的作用是描述一個裝置的地址資訊,準確的說是該裝置在IO地址空間的起始地址。

IO地址空間是讀寫和控制所有SoC上的外設的地址空間,可以理解為將SoC上的外設的暫存器地址對映成CPU可以理解的地址空間,例如上述程式碼中的0xff188888,CPU可以通過訪問以0xff188888開始的地址來讀寫和控制i2c(當然這個地址是我假設的)

在ARM架構中,Memory和IO被對映到一個同一個地址空間內,CPU訪問Memory和訪問IO使用相同的指令,但這一點在x86平臺中是不同的。

@符號還用與區分相同型別的外設,例如SoC上擁有4個i2c apapter,他們可以都叫i2c,但用@+地址來區分;當然你可以可以用aliase來定別名,這樣就使用加@了。

不同的dtsi定義了不同型別的引數,實際開發過程中可以根據檔名或者include關係找到你需要關注的裝置,當然我更喜歡用find/grep命令來幫助我定位裝置。

DeviceTree Compiler(DTC)

DTC 是編譯device tree原始檔的工具鏈,根據官方的介紹,DTC工具鏈將一種檔案格式作為輸入轉換成另一種檔案格式。典型的輸入檔案為可讀的dts文字檔案,輸出檔案是二進位制形式的dtb檔案。當然DTC同樣可以以二進位制的dtb檔案作為輸入,輸出dts檔案。

這意味著,使用DTC可以使dts檔案與dtb檔案相互轉換。

目前DTC支援輸入格式為:dts,dtb,fs;支援的輸出格式有:dtb,dts,asm。

CommandLine

DTC的命令格式為:

       dtc [options] [<input_filename>]

編譯dts,生成dtb

      dtc -I dts -O dtb -o output.dtb  file-a.dts file-b.dts 

反編譯dtb,生成dts

      dtc -I dtb -O dts -o output.dts  file-z.dtb

DeviceTree Bolb and dt.img

有關dtb以及dt.img的知識,我將會簡單介紹一下dtb、dtimg檔案的結構,這部分屬於進階的內容,將放到其他章節講解。

END

有關DeviceTree的基礎知識就介紹到這裡,後續會介紹DeviceTree的API以及常用裝置的dts開發方法。

參考資料

相關推薦

淺析Linux Device Tree

DeviceTree基礎 DeviceTree(以下簡稱DT)用於描述裝置資訊以及裝置於匯流排之間的層級關係,DT可用於描述絕大多數板級裝置的細節,包括CPU、記憶體、中斷、匯流排以及外設等,與DT相關的Object有dts、dtsi、dtc、dtb、dt.i

Linux Device Tree

疑問 裝置樹的使用 疑問

ARM Linux 3.x的設備樹(Device Tree)宋寶華

3rd else 命名 number 部分 kernel 傳統 rtc trigge 1. ARM Device Tree起源 Linus Torvalds在2011年3月17日的ARM Linux郵件列表宣稱“this whole ARM thing is a f*

轉:Linux設備樹(Device Tree)機制

十六進制 交互 mic 映射 0.0.0.0 內容 14. 字節 讀取 目錄 1. 設備樹(Device Tree)基本概念及作用 2. 設備樹的組成和使用 2.1. DTS和DTSI 2.2. DTC 2.3. DTB 2.4. Bootloader 3

i.mx6ul linux驅動開發—基於Device tree機制的驅動編寫

前言 Device Tree是一種用來描述硬體的資料結構,類似板級描述語言,起源於OpenFirmware(OF)。在目前廣泛使用的Linux kernel 2.6.x版本中,對於不同平臺、不同硬體,往往存在著大量的不同的、移植性差的板級描述程式碼,以達到對這些不同平臺和不同硬體特殊適配的需求

Linux Kernel Device Tree 配置框架

    背景:基於arm平臺的soc種類繁多,硬體資源和配置各不相同。這些平臺硬體相關的資訊在裝置樹出現之前,是在kernel/arch/arm/plat-xxx目錄和kernel/arch/arm/mach-xxx目錄下硬編碼的。在kernel看來,這些硬體細節程式碼只不過是些垃圾,需要

基於tiny4412的Linux核心移植(支援device tree)(三)

https://www.cnblogs.com/pengdonglin137/p/5146791.html 閱讀目錄(Content) 作者資訊 平臺簡介 注意 一、裝置樹反編譯 二、在u-boot列印資訊 三、開啟Linux核心啟動早期的log 四、在核心自解壓時dump記憶體 五、C

基於tiny4412的Linux核心移植(支援device tree)(二)

https://www.cnblogs.com/pengdonglin137/p/5143516.html 閱讀目錄(Content) 作者資訊 平臺簡介 步驟 回到頂部(go to top) 作者資訊 作者: 彭東林 郵箱:[email protected] QQ:4

基於tiny4412的Linux核心移植(支援device tree)(一)

https://www.cnblogs.com/pengdonglin137/p/5137941.html 閱讀目錄(Content) 作者資訊 平臺簡介 概述 步驟 回到頂部(go to top) 作者資訊 作者: 彭東林 郵箱:[email protected] Q

Linux DTS(Device Tree Source)裝置樹詳解

一.什麼是DTS?為什麼要引入DTS? DTS即Device Tree Source 裝置樹原始碼, Device Tree是一種描述硬體的資料結構,它起源於 OpenFirmware (OF)。 在Linux 2.6中,ARM架構的板極硬體細節過多地被硬編碼在arc

ARM Linux 3.x的裝置樹(Device Tree

宋寶華 Barry Song <[email protected]>本文部分案例和文字英文原版來源於 http://devicetree.org/Device_Tree_Usage1.    ARM Device Tree起源Linus Torvalds

ARM Linux 3.x 的裝置樹(Device Tree)之DTB、DTS

1、ARM Device Tree起源 Linus Torvalds在2011年3月17日的ARM Linux郵件列表宣稱“this whole ARM thing is a f*cking pain in the ass”,引發ARM Linux社群的地震,

Linux 裝置樹(Device Tree)簡介

DTS (device tree source)   .dts檔案是一種ASCII 文字格式的Device Tree描述,此文字格式非常人性化,適合人類的閱讀習慣。基本上,在ARM Linux在,一個

[ZedBoard移植嵌入式Linux教程(4)]建立裝置樹(Device-Tree)檔案dts

裝置樹用於硬體和軟體之間的資訊互動,也就是將ZedBoard的硬體資訊傳遞給linux核心,避免在linux核心中硬編碼而影響在其他平臺上的可移植性。裝置樹一般以兩種檔案格式存在,一個是dts檔案,也就是文字檔案,便於閱讀,另外一種是dtb檔案,是二進位制格式,是dts使用d

Linux DTS(Device Tree Source)裝置樹詳解之一(背景基礎知識篇)

本系列導航: 一.什麼是DTS?為什麼要引入DTS? DTS即Device Tree Source 裝置樹原始碼, Device Tree是一種描述硬體的資料結構,它起源於 OpenFirmware (OF)。 在Linux 2.6中,ARM架構的板極硬體細節過

Device Tree(四)linux-4.19.10 板級移植

1、修改Makefile ARCH ?= arm CROSS_COMPILE ?= arm-linux-gnueabihf- 如果發現:/tmp/cc8nFJm8.s:549: Error: garbage following instruction -- `d

Linux DTS(Device Tree Source)裝置樹詳解之二(dts匹配及發揮作用的流程篇)

本系列導航: 有上一篇文章,我們瞭解了dts的背景知識和相關基礎,這次我們對應實際裝置進行一下相關分析。 DTS裝置樹的匹配過程 一個dts檔案確定一個專案,多個專案可以包含同一個dtsi檔案。找到該專案對應的dts檔案即找到了該裝置樹的根節點。 kernel

Linux 中斷(irq)控制器以及device tree設定

GPIO相關中斷(高通平臺為例) gpio相關的中斷控制器(msm_tlmm_irq) 初始化 (1) IRQCHIP_DECLARE定義irq chip #define IRQCHIP_DECLARE(name,compstr,fn)

高通平臺msm8953 Linux DTS(Device Tree Source)裝置樹詳解之二(DTS裝置樹匹配過程)

本系列導航:有上一篇文章,我們瞭解了dts的背景知識和相關基礎,這次我們對應實際裝置進行一下相關分析。DTS裝置樹的匹配過程一個dts檔案確定一個專案,多個專案可以包含同一個dtsi檔案。找到該專案對應的dts檔案即找到了該裝置樹的根節點。kernel\arch\arm\bo

linux 讓led閃爍起來,by timer,device tree

[email protected]{compatible="cma9,jaguar_led";led-gpios=<&gpio_cs 0 1>;cma9,default-trigger = "timer";status = "okay";};