1. 程式人生 > >linux裝置樹

linux裝置樹

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: [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. 相關推薦

    ARM Linux裝置

    1 ARM裝置樹 DT: Device Tree FDT: Flattened DeviceTree OF: Open Firmware(開啟韌體,這個字首在後面的api中會用到) DTS : device tree souke DTSI: device tree sourc

    Linux裝置語法詳解【轉】

    轉自:https://www.cnblogs.com/xiaojiang1025/p/6131381.html 概念 Linux核心從3.x開始引入裝置樹的概念,用於實現驅動程式碼與裝置資訊相分離。在裝置樹出現以前,所有關於裝置的具體資訊都要寫在驅動裡,一旦外圍裝置變化,驅動程式碼就要重寫。引入了裝置樹之

    04-Linux裝置系列-GPIO驅動實踐

    1. 前言 GPIO驅動開發可能算是Linux核心裝置驅動開發中最為簡單、最常見的一個方向,對於開發板的按鍵、LED、蜂鳴器、電源控制等模組,可能都是使用GPIO實現的。Linux核心的GPIO子系統在核心不斷的演進過程中進行了多次的重構,本文的第二

    Linux裝置語法詳解

    概念 Linux核心從3.x開始引入裝置樹的概念,用於實現驅動程式碼與裝置資訊相分離。在裝置樹出現以前,所有關於裝置的具體資訊都要寫在驅動裡,一旦外圍裝置變化,驅動程式碼就要重寫。引入了裝置樹之後,驅動程式碼只負責處理驅動的邏輯,而關於裝置的具體資訊存放到裝置樹檔案中,

    Linux裝置使用

    本頁面介紹瞭如何為新machine編寫裝置樹檔案。它旨在提供裝置樹概念的概述以及它們如何用於描述machine。 有關裝置樹資料格式的完整技術說明,請參閱ePAPR v1.1規範。ePAPR規範比本頁面介紹的基本主題包含更多詳細資訊,請參閱此頁面以獲取本頁未涵蓋的更高階用法

    (最新核心3.4)Linux 裝置載入I2C client adapter 的流程(核心3.4 高通)

    BLSP(BAM Low-Speed Peripheral) , 每一個BLSP含有兩個QUP, 每一個QUP可以被配置為I2C, SPI, UART, UIM介面, BLSP是高通對於低速介面的一種管理方式。 [email protec

    linux裝置筆記__基於msm8x10的基本分析

    由文章,linux裝置樹筆記__dts基本概念及語法,我們知道了基本概念,知道了大概的裝置樹節點及其屬性,而節點下的屬性大多是自定義,除了保留的幾個屬性,大多從.dts是無法知道其用途的,這個就需要看驅動是如何解析屬性值的了,這點也可作技術細節的部分隱藏。 在原始碼的ms

    linux裝置

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

    第18章 ARM Linux裝置之四(常用的OF API)

    18.4 常用的OF API除了前文介紹的of_machine_is_compatible()、of_device_is_compatible()等常用函式以外,在Linux的BSP和驅動程式碼中,經常會使用到一些Linux中其他裝置樹的API,這些API通常被冠以of_字首

    linux裝置中pinctrl的配置(上)

    最近在移植linux,用到kernel版本為3.18.22和4.1.3,在高版本的核心原始碼中用到了裝置樹(device-tree),裝置樹中用到pinctrl的配置,記錄一下。 1、普通設定 在配置串列埠時,pinctrl的配置資訊如下所示: <span st

    linux裝置中pinctrl的配置(下)

    上一篇記錄了裝置樹檔案中管腳普通配置的查詢與確定,這篇介紹一下特殊的配置。 首先還是先看程式碼,看看到底特殊到哪裡。 <span style="font-size:14px;"> pi

    Linux 裝置(Device Tree)簡介

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

    linux 裝置及節點引用

    說了這麼半天,跟引入裝置樹有什麼關係呢?華清教學使用的開發板(A8/A9)都使用DM9000網絡卡晶片。DM9000驅動是開源的,在主線核心原始碼中就有。我們每次基於A8/A9板子移植的時候,DM9000驅動並沒有修改過,僅僅是選配了下,主要的工作是在板級檔案中添加了裝置資訊。DM9000驅動使用的是plat

    linux裝置詳解-韋東山-專題視訊課程

    linux裝置樹詳解—150人已學習 課程介紹        現在的linux核心(Linux3.X)都已支援裝置樹機制(dts),不管你是玩核心還是玩驅動,一定會碰到裝置樹,而網上雖然有很多部落格,但都講的不夠清晰,看了還是不懂,半桶水,學員急需一套講解裝置樹比較透徹的課程

    linux裝置中的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社群的地震

    Linux裝置學習日記(一)裝置簡單介紹

    一、linux裝置樹簡介1.    裝置樹是一種描述硬體的資料結構,它起源於openfirmware,採用裝置樹後,許多硬體的細節可以直接通過它傳遞給linux,而不需要在核心中進行大量冗餘編碼。2.    裝置樹由一系列被命名的節點(Node)和屬性(property)組成

    Linux驅動】Linux裝置語法詳解

    1 概念Linux核心從3.x開始引入裝置樹的概念,用於實現驅動程式碼與裝置資訊相分離。在裝置樹出現以前,所有關於裝置的具體資訊都要寫在驅動裡,一旦外圍裝置變化,驅動程式碼就要重寫。引入了裝置樹之後,驅動程式碼只負責處理驅動的邏輯,而關於裝置的具體資訊存放到裝置樹檔案中,這樣,如果只是硬體介面資訊的變化而沒有

    我眼中的Linux裝置(三 屬性)

    三 屬性(property)device_type = "memory"就是一個屬性,等號前邊是屬性,後邊是值。節點是一個邏輯上相對獨立的實體,屬性是用來描述節點特性的,根據需要一個節點由0個,1個或多個屬性表示節點的特性。一個屬性由名字和值兩部分組成。和節點的名字類似,規範

    第二課:linux裝置的規範(dts和dtb)

    轉載請註明文章地址 http://wiki.100ask.org/Linux_devicetree 第01節_DTS格式 dts檔案通過編譯生成dtb格式檔案 屬性的定義 value取值型別 屬性名=值只有三種取值 第一種 <1 0x3

    第一課:linux裝置的引入與體驗(基於linux4.19核心版本)

    轉載請註明原文地址:http://wiki.100ask.org/Linux_devicetree 本套視訊面向如下三類學員: 有Linux驅動開發基礎的人, 可以挑感興趣的章節觀看; 沒有Linux驅動開發基礎但是願意學習的人,請按順序全部觀看,我會