1. 程式人生 > >Device Tree中的.dts和dtsi檔案介紹

Device Tree中的.dts和dtsi檔案介紹

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社群的地震,隨後ARM社群進行了一系列的重大修正。在過去的ARM Linux中,arch/arm/plat-xxx和arch/arm/mach-xxx中充斥著大量的垃圾程式碼,相當多數的程式碼只是在描述板級細節,而這些板級細節對於核心來講,不過是垃圾,如板上的platform裝置、resource、i2c_board_info、spi_board_info以及各種硬體的platform_data。讀者有興趣可以統計下常見的s3c2410、s3c6410等板級目錄,程式碼量在數萬行。

社群必須改變這種局面,於是PowerPC等其他體系架構下已經使用的Flattened Device Tree(FDT)進入ARM社群的視野。Device Tree是一種描述硬體的資料結構,它起源於 OpenFirmware (OF)。在Linux 2.6中,ARM架構的板極硬體細節過多地被硬編碼在arch/arm/plat-xxx和arch/arm/mach-xxx,採用Device Tree後,許多硬體的細節可以直接透過它傳遞給Linux,而不再需要在kernel中進行大量的冗餘編碼。
Device Tree由一系列被命名的結點(node)和屬性(property)組成,而結點本身可包含子結點。所謂屬性,其實就是成對出現的name和value。在Device Tree中,可描述的資訊包括(原先這些資訊大多被hard code到kernel中):

  • CPU的數量和類別
  • 記憶體基地址和大小
  • 匯流排和橋
  • 外設連線
  • 中斷控制器和中斷使用情況
  • GPIO控制器和GPIO使用情況
  • Clock控制器和Clock使用情況
它基本上就是畫一棵電路板上CPU、匯流排、裝置組成的樹,Bootloader會將這棵樹傳遞給核心,然後核心可以識別這棵樹,並根據它展開出Linux核心中的platform_device、i2c_client、spi_device等裝置,而這些裝置用到的記憶體、IRQ等資源,也被傳遞給了核心,核心會將這些資源繫結給展開的相應的裝置。

2.    Device Tree組成和結構

整個Device Tree牽涉面比較廣,即增加了新的用於描述裝置硬體資訊的文字格式,又增加了編譯這一文字的工具,同時Bootloader也需要支援將編譯後的Device Tree傳遞給Linux核心。

DTS (device tree source)

.dts檔案是一種ASCII 文字格式的Device Tree描述,此文字格式非常人性化,適合人類的閱讀習慣。基本上,在ARM Linux在,一個.dts檔案對應一個ARM的machine,一般放置在核心的arch/arm/boot/dts/目錄。由於一個SoC可能對應多個machine(一個SoC可以對應多個產品和電路板),勢必這些.dts檔案需包含許多共同的部分,Linux核心為了簡化,把SoC公用的部分或者多個machine共同的部分一般提煉為.dtsi,類似於C語言的標頭檔案。其他的machine對應的.dts就include這個.dtsi。譬如,對於VEXPRESS而言,vexpress-v2m.dtsi就被vexpress-v2p-ca9.dts所引用, vexpress-v2p-ca9.dts有如下一行:
/include/ "vexpress-v2m.dtsi"
當然,和C語言的標頭檔案類似,.dtsi也可以include其他的.dtsi,譬如幾乎所有的ARM SoC的.dtsi都引用了skeleton.dtsi。
.dts(或者其include的.dtsi)基本元素即為前文所述的結點和屬性:
  1. / {  
  2.     node1 {  
  3.         a-string-property = "A string";  
  4.         a-string-list-property = "first string", "second string";  
  5.         a-byte-data-property = [0x01 0x23 0x34 0x56];  
  6.         child-node1 {  
  7.             first-child-property;  
  8.             second-child-property = <1>;  
  9.             a-string-property = "Hello, world";  
  10.         };  
  11.         child-node2 {  
  12.         };  
  13.     };  
  14.     node2 {  
  15.         an-empty-property;  
  16.         a-cell-property = <1 2 3 4>; /* each number (cell) is a uint32 */  
  17.         child-node1 {  
  18.         };  
  19.     };  
  20. };  
上述.dts檔案並沒有什麼真實的用途,但它基本表徵了一個Device Tree原始檔的結構:
1個root結點"/";
root結點下面含一系列子結點,本例中為"node1" 和 "node2";
結點"node1"下又含有一系列子結點,本例中為"child-node1" 和 "child-node2";
各結點都有一系列屬性。這些屬性可能為空,如" an-empty-property";可能為字串,如"a-string-property";可能為字串陣列,如"a-string-list-property";可能為Cells(由u32整陣列成),如"second-child-property",可能為二進位制數,如"a-byte-data-property"。
下面以一個最簡單的machine為例來看如何寫一個.dts檔案。假設此machine的配置如下:
1個雙核ARM Cortex-A9 32位處理器;
ARM的local bus上的記憶體對映區域分佈了2個串列埠(分別位於0x101F1000 和 0x101F2000)、GPIO控制器(位於0x101F3000)、SPI控制器(位於0x10170000)、中斷控制器(位於0x10140000)和一個external bus橋;
External bus橋上又連線了SMC SMC91111 Ethernet(位於0x10100000)、I2C控制器(位於0x10160000)、64MB NOR Flash(位於0x30000000);
External bus橋上連線的I2C控制器所對應的I2C總線上又連線了Maxim DS1338實時鐘(I2C地址為0x58)。
其對應的.dts檔案為:
  1. / {  
  2.     compatible = "acme,coyotes-revenge";  
  3.     #address-cells = <1>;  
  4.     #size-cells = <1>;  
  5.     interrupt-parent = <&intc>;  
  6.     cpus {  
  7.         #address-cells = <1>;  
  8.         #size-cells = <0>;  
  9.         [email protected] {  
  10.             compatible = "arm,cortex-a9";  
  11.             reg = <0>;  
  12.         };  
  13.         [email protected] {  
  14.             compatible = "arm,cortex-a9";  
  15.             reg = <1>;  
  16.         };  
  17.     };  
  18.     [email protected] {  
  19.         compatible = "arm,pl011";  
  20.         reg = <0x101f0000 0x1000 >;  
  21.         interrupts = < 1 0 >;  
  22.     };  
  23.     [email protected] {  
  24.         compatible = "arm,pl011";  
  25.         reg = <0x101f2000 0x1000 >;  
  26.         interrupts = < 2 0 >;  
  27.     };  
  28.     [email protected] {  
  29.         compatible = "arm,pl061";  
  30.         reg = <0x101f3000 0x1000  
  31.                0x101f4000 0x0010>;  
  32.         interrupts = < 3 0 >;  
  33.     };  
  34.     intc: [email protected] {  
  35.         compatible = "arm,pl190";  
  36.         reg = <0x10140000 0x1000 >;  
  37.         interrupt-controller;  
  38.         #interrupt-cells = <2>;  
  39.     };  
  40.     [email protected] {  
  41.         compatible = "arm,pl022";  
  42.         reg = <0x10115000 0x1000 >;  
  43.         interrupts = < 4 0 >;  
  44.     };  
  45.     external-bus {  
  46.         #address-cells = <2>  
  47.         #size-cells = <1>;  
  48.         ranges = <0 0  0x10100000   0x10000     // Chipselect 1, Ethernet  
  49.                   1 0  0x10160000   0x10000     // Chipselect 2, i2c controller  
  50.                   2 0  0x30000000   0x1000000>; // Chipselect 3, NOR Flash  
  51.         [email protected],0 {  
  52.             compatible = "smc,smc91c111";  
  53.             reg = <0 0 0x1000>;  
  54.             interrupts = < 5 2 >;  
  55.         };  
  56.         [email protected],0 {  
  57.             compatible = "acme,a1234-i2c-bus";  
  58.             #address-cells = <1>;  
  59.             #size-cells = <0>;  
  60.             reg = <1 0 0x1000>;  
  61.             interrupts = < 6 2 >;  
  62.             [email protected] {  
  63.                 compatible = "maxim,ds1338";  
  64.                 reg = <58>;  
  65.                 interrupts = < 7 3 >;  
  66.             };  
  67.         };  
  68.         [email protected],0 {  
  69.             compatible = "samsung,k8f1315ebm", "cfi-flash";  
  70.             reg = <2 0 0x4000000>;  
  71.         };  
  72.     };  
  73. };  
上述.dts檔案中,root結點"/"的compatible 屬性compatible = "acme,coyotes-revenge";定義了系統的名稱,它的組織形式為:<manufacturer>,<model>。Linux核心透過root結點"/"的compatible 屬性即可判斷它啟動的是什麼machine。
在.dts檔案的每個裝置,都有一個compatible 屬性,compatible屬性使用者驅動和裝置的繫結。compatible 屬性是一個字串的列表,列表中的第一個字串表徵了結點代表的確切裝置,形式為"<manufacturer>,<model>",其後的字串表徵可相容的其他裝置。可以說前面的是特指,後面的則涵蓋更廣的範圍。如在arch/arm/boot/dts/vexpress-v2m.dtsi中的Flash結點:
  1. [email protected],00000000 {  
  2.      compatible = "arm,vexpress-flash", "cfi-flash";  
  3.      reg = <0 0x00000000 0x04000000>,  
  4.      <1 0x00000000 0x04000000>;  
  5.      bank-width = <4>;  
  6.  };  
compatible屬性的第2個字串"cfi-flash"明顯比第1個字串"arm,vexpress-flash"涵蓋的範圍更廣。
再比如,Freescale MPC8349 SoC含一個串列埠裝置,它實現了國家半導體(National Semiconductor)的ns16550 暫存器介面。則MPC8349串列埠裝置的compatible屬性為compatible = "fsl,mpc8349-uart", "ns16550"。其中,fsl,mpc8349-uart指代了確切的裝置, ns16550代表該裝置與National Semiconductor 的16550 UART保持了暫存器相容。
接下來root結點"/"的cpus子結點下面又包含2個cpu子結點,描述了此machine上的2個CPU,並且二者的compatible 屬性為"arm,cortex-a9"。
注意cpus和cpus的2個cpu子結點的命名,它們遵循的組織形式為:<name>[@<unit-address>],<>中的內容是必選項,[]中的則為可選項。name是一個ASCII字串,用於描述結點對應的裝置型別,如3com Ethernet介面卡對應的結點name宜為ethernet,而不是3com509。如果一個結點描述的裝置有地址,則應該給出@unit-address。多個相同型別裝置結點的name可以一樣,只要unit-address不同即可,如本例中含有[email protected][email protected]以及[email protected][email protected]這樣的同名結點。裝置的unit-address地址也經常在其對應結點的reg屬性中給出。ePAPR標準給出了結點命名的規範。
可定址的裝置使用如下資訊來在Device Tree中編碼地址資訊:
  •     reg
  •     #address-cells
  •     #size-cells
其中reg的組織形式為reg = <address1 length1 [address2 length2] [address3 length3] ... >,其中的每一組address length表明了裝置使用的一個地址範圍。address為1個或多個32位的整型(即cell),而length則為cell的列表或者為空(若#size-cells = 0)。address 和 length 欄位是可變長的,父結點的#address-cells和#size-cells分別決定了子結點的reg屬性的address和length欄位的長度。在本例中,root結點的#address-cells = <1>;和#size-cells = <1>;決定了serial、gpio、spi等結點的address和length欄位的長度分別為1。cpus 結點的#address-cells = <1>;和#size-cells = <0>;決定了2個cpu子結點的address為1,而length為空,於是形成了2個cpu的reg = <0>;和reg = <1>;。external-bus結點的#address-cells = <2>和#size-cells = <1>;決定了其下的ethernet、i2c、flash的reg欄位形如reg = <0 0 0x1000>;、reg = <1 0 0x1000>;和reg = <2 0 0x4000000>;。其中,address欄位長度為0,開始的第一個cell(0、1、2)是對應的片選,第2個cell(0,0,0)是相對該片選的基地址,第3個cell(0x1000、0x1000、0x4000000)為length。特別要留意的是i2c結點中定義的 #address-cells = <1>;和#size-cells = <0>;又作用到了I2C總線上連線的RTC,它的address欄位為0x58,是裝置的I2C地址。
root結點的子結點描述的是CPU的檢視,因此root子結點的address區域就直接位於CPU的memory區域。但是,經過匯流排橋後的address往往需要經過轉換才能對應的CPU的memory對映。external-bus的ranges屬性定義了經過external-bus橋後的地址範圍如何對映到CPU的memory區域。
  1. ranges = <0 0  0x10100000   0x10000     // Chipselect 1, Ethernet  
  2.           1 0  0x10160000   0x10000     // Chipselect 2, i2c controller  
  3.           2 0  0x30000000   0x1000000>; // Chipselect 3, NOR Flash  
ranges是地址轉換表,其中的每個專案是一個子地址、父地址以及在子地址空間的大小的對映。對映表中的子地址、父地址分別採用子地址空間的#address-cells和父地址空間的#address-cells大小。對於本例而言,子地址空間的#address-cells為2,父地址空間的#address-cells值為1,因此0 0  0x10100000   0x10000的前2個cell為external-bus後片選0上偏移0,第3個cell表示external-bus後片選0上偏移0的地址空間被對映到CPU的0x10100000位置,第4個cell表示對映的大小為0x10000。ranges的後面2個專案的含義可以類推。
Device Tree中還可以中斷連線資訊,對於中斷控制器而言,它提供如下屬性:
interrupt-controller – 這個屬性為空,中斷控制器應該加上此屬性表明自己的身份;
#interrupt-cells – 與#address-cells 和 #size-cells相似,它表明連線此中斷控制器的裝置的interrupts屬性的cell大小。
在整個Device Tree中,與中斷相關的屬性還包括:
interrupt-parent – 裝置結點透過它來指定它所依附的中斷控制器的phandle,當結點沒有指定interrupt-parent 時,則從父級結點繼承。對於本例而言,root結點指定了interrupt-parent = <&intc>;其對應於intc: i[email protected],而root結點的子結點並未指定interrupt-parent,因此它們都繼承了intc,即位於0x10140000的中斷控制器。
interrupts – 用到了中斷的裝置結點透過它指定中斷號、觸發方法等,具體這個屬性含有多少個cell,由它依附的中斷控制器結點的#interrupt-cells屬性決定。而具體每個cell又是什麼含義,一般由驅動的實現決定,而且也會在Device Tree的binding文件中說明。譬如,對於ARM GIC中斷控制器而言,#interrupt-cells為3,它3個cell的具體含義Documentation/devicetree/bindings/arm/gic.txt就有如下文字說明:
  1. 01   The 1st cell is the interrupt type; 0 for SPI interrupts, 1 for PPI  
  2. 02   interrupts.  
  3. 03  
  4. 04   The 2nd cell contains the interrupt number for the interrupt type.  
  5. 05   SPI interrupts are in the range [0-987].  PPI interrupts are in the  
  6. 06   range [0-15].  
  7. 07  
  8. 08   The 3rd cell is the flags, encoded as follows:  
  9. 09         bits[3:0] trigger type and level flags.  
  10. 10                 1 = low-to-high edge triggered  
  11. 11                 2 = high-to-low edge triggered  
  12. 12                 4 = active high level-sensitive  
  13. 13                 8 = active low level-sensitive  
  14. 14         bits[15:8] PPI interrupt cpu mask.  Each bit corresponds to each of  
  15. 15         the 8 possible cpus attached to the GIC.  A bit set to '1' indicated  
  16. 16         the interrupt is wired to that CPU.  Only valid for PPI interrupts.  
另外,值得注意的是,一個裝置還可能用到多箇中斷號。對於ARM GIC而言,若某裝置使用了SPI的168、169號2箇中斷,而言都是高電平觸發,則該裝置結點的interrupts屬性可定義為:interrupts = <0 168 4>, <0 169 4>;
除了中斷以外,在ARM Linux中clock、GPIO、pinmux都可以透過.dts中的結點和屬性進行描述。

相關推薦

Device Tree的.dtsdtsi檔案介紹

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社群的地震,隨後A

Android開發專案的build.gradle檔案介紹

在開發android專案中,我們通常會遇到兩個build.gradle檔案。如下圖所示: 一個用於整個專案,另一個用於app應用模組。應用於整個專案的內容很少,沒啥好解釋的,內容保持預設不變就行了。我們要了解和經常編輯的是app/build.grad

xmlhttpreadyStatestatus的介紹

xmlhttp.readyState的值及解釋: 0:請求未初始化(還沒有呼叫 open())。 1:請求已經建立,但是還沒有傳送(還沒有呼叫 send())。 2:請求已傳送,正在處理中(通常現在可以從響應中獲取內容頭)。 3:請求在處理中;通常響應中已有部分資料可用了,但是伺服器

JVM記憶體GC的介紹

最近聽聞很多裁員潮,寒冬潮的訊息,所以才會有下面這些總結,給道友準備,也是為自己! 希望自己用不到................. 記憶體分佈 jvm將記憶體分為了堆,方法區,程式計數器,棧(虛擬機器棧),本地方法棧5個區域,有些是執行緒共有的有的是執行緒共享的。下面就簡單就這幾個區域做簡單說明。 程

FPGA開發sofelf檔案的合併與格式轉換

0. 本文目的     有關sof和elf檔案的合併方法非常多,但真正好用而且經得起推敲的寥寥無幾。通過相關資料的學習以及工程實踐,現將個人的操作方法及收穫進行總結,希望能給正在學習FPGA的夥伴們提供一點點幫助!     Nios工程開發包括兩個環節,前期的核心硬體開發

Eclipse.setting目錄下檔案介紹

Eclipse專案中系統檔案介紹 一. 寫在前面 文章較長,可以直接到感興趣的段落,或者直接關鍵字搜尋; 請原諒作者掌握的程式語言少,這裡只研究Java相關的專案; 每一個檔案僅僅做一個常見內容的簡單介紹,這些知識多數來自於實踐理解和網路搜尋,可能會不全面,更詳細的可以看

springbootfastJsonproperties檔案佔位符解析

1.介紹    fastJson是阿里巴巴出品的一款速度極快的json解析工具    properties配置檔案有時無法解析某些佔位符 2.使用    直接放到springboot啟動類中即可

敏捷開發團隊POSM角色介紹

敏捷開發中的PO即Product Owner,字面意思是產品或業務負責人,即熟悉該產品所有業務相關的邏輯、流程、設定等方面事宜的人員,一般可由產品經理擔任,也可由熟悉業務的開發人員擔任。如果敏捷團隊是在一起辦公的(指一個辦公室內坐在一起的),建議由產品經理擔任,本身產品經理

關於device tree的interrupts選項

隨著Linux的發展,dts技術是大勢所趨。裡面的interrupts = <   >這個裡面的是1個數,有的是2個數,有的是3個數。這裡囉嗦兩句,筆記一下。 這個數目,是由這個屬性來定的。#interrupt-cells ,如果當前節點找不到,就是跟隨父節點

移植u-boot-2011.03到S3C2440(utu2440)的方法與步驟###8. u-boot引導啟動nand flash核心檔案系統cramfs使用者檔案系統yaffs2支援

rivers/rtc/hctosys.c: unable to open rtc device (rtc0)uncorrectable error : <3>uncorrectable error : <3>end_request: I/O error, dev mtdblock2, 

c中標頭檔案在cpp檔案引用.h檔案引用的思考

       我們在編寫程式中標頭檔案是經常使用的。但是標頭檔案是應該包含在.H檔案中還是在.cpp檔案中。在這個當中有什麼樣去區別呢。  假如說我們編寫了一個a.cpp  。我們將a.cpp檔案的變數和函式申明在a.h中。在a.h檔案有使用了b.中定義的型別type1資料

跟我來學小程式(一)專案目錄專案檔案介紹

大家好,我是一個愛舉鐵的程式設計師Shr。 本篇檔案介紹小程式專案的目錄和專案檔案。 原始碼地址: https://github.com/ShrMus/wechat_xcx/tree/master/demo_20180603 一、新建專案 開啟微信web

根據正則表示式匹配頁面jscss檔案

          // 匹配           List<string> srcList = new List<string>();           List<string> linkList = new List<string>();   

Amazon EFS價格_亞馬遜雲設定擴充套件檔案儲存

每月計費的儲存量按照全月內使用的平均儲存空間計算。您的儲存用量以“GB/月”為單位進行衡量,月底合計該值,得出您的月度費用。 每月計費的吞吐量按照該月的平均預置吞吐量計算。您的吞吐量以“MB/s/月”為單位進行衡量,月底合計該值,得出您的月度費用。

Amazon EFS常見問題_亞馬遜雲設定擴充套件檔案儲存

問: 什麼是預置吞吐量?應在何時使用? 預置吞吐量使 Amazon EFS 客戶能夠預置檔案系統的吞吐量(無需考慮儲存的資料量),從而優化檔案系統的吞吐效能,以滿足應用程式的需求。 Amazon EFS 預置吞吐量適用於吞吐量 (MB/

Spring原始碼學習--SpringIOCAOP的介紹

前言: 控制反轉(Inversion of Control,英文縮寫為IoC); 面向切面程式設計(Aspect Oriented Programming,英文縮寫為AOP) 我們是在使用spring框架的過程中,很大一部分是為了使用IoC(依賴注入),和

servlet學習之servletcookiesession的介紹

前言 記得在校招的時候總是會問及怎樣解決http的無狀態問題,其實自己知道有隱藏表單,cookie,令牌,session等技術可是具體的流程及由來,還有應用我是一臉懵逼的。。。 大綱 Cookie概述Cookie使用的三個步驟Cookie的機制Cookie的安全問題Sess

Java物件詳細介紹

static void main(String[] args) { //1 int i = 2; changeValue(2);//方法中x複製了i的值,為2,方法執行結束x=6,但是i的值不變 System.out.prin

VSbinobj檔案引發的問題

   在敲機房收費系統的時候通常都會遇到這個問題:“未能載入檔案或程式集“DAL”或它的某一個依賴項。系統找不到指定的檔案”。     解決方案:      修改將DAL的輸出目錄 修改到UI/bin

父容器div內的子元素div為float時,父元素無法撐開(或高度自適應)的解決方式以及csspositionfloat的介紹

先簡單給出父元素無法高度自適應時的解決方案:       第一種:在父容器上設定 overflow:auto或者hidden可以讓它自動包含子元素,從而具有了實際的height值。       第二種:在子元素的最下面加上一個 空元素,並且設定clear:both,但