理解Device Tree Usage

来源:https://www.cnblogs.com/djw316/archive/2019/03/13/10524820.html
-Advertisement-
Play Games

英語原文地址: htttp://devicetree.org/Device_Tree_Usage 本文介紹如何為新的機器或板卡編寫設備樹(Device Tree), 它旨在概要性的介紹設備樹概念,以及如何使用它們來描述機器或者板卡。 有關設備樹數據格式的完整技術描述,請參閱ePAPR v1.1規範。 ...


英語原文地址: htttp://devicetree.org/Device_Tree_Usage 本文介紹如何為新的機器或板卡編寫設備樹(Device Tree), 它旨在概要性的介紹設備樹概念,以及如何使用它們來描述機器或者板卡。 有關設備樹數據格式的完整技術描述,請參閱ePAPR v1.1規範。 ePAPR技術規範比本文所介紹的基礎主題更加詳細,所以請參閱它瞭解本頁未涉及的更高級用法。 ePAPR目前正在用Devicetree規範文檔的新名稱進行更新。  

1 基礎數據結構

設備樹(Device Tree)是一種包含節點和屬性的簡單樹形結構。屬性是鍵值對,節點則可能包含屬性和子節點。 例如,下麵是一個.dts格式的簡單設備樹:
/dts-v1/;
 
/ {
    node1 {
        a-string-property = "A string";
        a-string-list-property = "first string", "second string";
        // hex is implied in byte arrays. no '0x' prefix is required
        a-byte-data-property = [01 23 34 56];
        child-node1 {
            first-child-property;
            second-child-property = <1>;
            a-string-property = "Hello, world";
        };
        child-node2 {
        };
    };
    node2 {
        an-empty-property;
        a-cell-property = <1 2 3 4>; /* each number (cell) is a uint32 */
        child-node1 {
        };
    };
};

 

上面這個設備樹,顯然沒有實際用處,因為它沒有描述任何信息,但是它確實顯示了節點的結構和屬性:
  • 一個簡單的root節點:“/”
  • 一組子節點:“node1”和“node2”
  • 一組node1的子節點:“child-node1”和“child-node2”
  • 一堆分散在設備樹中的屬性
屬性是簡單的鍵-值對,其中的值可以是空的,也可以包含任意的位元組流。雖然數據類型沒有編碼到數據結構中,但是有一些基本的數據表示可以在設備樹源文件中表示。
  • 文本字元串(以null結尾),用雙引號表示:
    • string-property = "a string";
  • ‘cell’是被<>括弧括起來的32bit無符號int數
    • cell-property = <0xbeef 123 0xabcd1234>;
  •  二進位數據是被[]括弧括起來
    • binary-property = [0x01 0x23 0x45 0x67];
  •  不同類型的數據,可以以逗號“,”串起來
    •  mixed-property = "a string", [0x01 0x23 0x45 0x67], <0x12345678>;
  •  逗號“,”也可以用來表示字元串列表:
    •  string-list = "red fish", "blue fish";

2 基礎概念Basic Concepts

為了理解設備樹(device tree)如何使用,我們將從一個簡單的設備(machine)開始,建立一個設備樹(device tree),然後一步一步描述它。

2.1示例設備(sample machine)

假設有這樣一臺虛擬的設備(基於ARM的通用版本),由“Acme”公司生產,名為“Cpyote's Revenge”:
  • 一個32位寬的ARM CPU
  • 處理器本地匯流排連接到記憶體映射串口、spi匯流排控制器、i2c控制器、中斷控制器和外部匯流排橋
  • 從0地址開始的256MB 位元組的SDRAM
  • 2個串口,寄存器基地址分別是0x101F1000和0x101F2000
  • GPIO的控制寄存器的基地址是0x101F3000
  • SPI的控制寄存器的基地址是0x10170000,並掛載下列設備
    • MMC slot,SS管腳連接到GPIO1
  • 外部匯流排橋接著下列設備
    • SMC SMC91111網路設備連接到外部匯流排,基地址是0x10100000
    • i2c 控制寄存器基地址是0x10160000,並掛載下列設備
      • Maxim DS1338實時時鐘,其地址是1101000(0x58)
    • 64M的Nor flash基地址是0x30000000

2.2 初始化結構體(Initial structure)

第一步是為設備鋪設骨架, 這是有效設備樹所需的最小結構。在這一階段,你需要能唯一的標識設備。
/dts-v1/;
 
/ {
    compatible = "acme,coyotes-revenge";
};
  “compatible”表明系統的名字。它包含一個以“製造商”,“品牌”形式組成的字元串。準確的表明設備非常重要,而且需要包含製造商的名稱以避免命名衝突。 由於操作系統將使用compatible值來決定如何在機器上運行,因此將正確的數據寫入此屬性中非常重要。理論上,一個操作系統唯一識別一臺設備只要有“compatible”屬性就夠了。如果所有設備細節都是硬編碼的,那麼操作系統可以專門在Device Tree的最頂層的“compatible”屬性中查找 "acme,coyotes-revenge"即可。

2.3 CPUs

下一步是描述每一個CPU。添加一個名為“cpus”的容器節點,為每一個CPU創建一個子節點。在當前的例子里,該系統是一個源自ARM的雙核Cortex A9系統。
/dts-v1/;
 
/ {
    compatible = "acme,coyotes-revenge";
    cpus {
        cpu@0 {
            compatible = "arm,cortex-a9";
        };
        cpu@1 {
            compatible = "arm,cortex-a9";
        };
    };
};
  每個CPU節點的“compatible”的屬性都是一個字元串,以“製造商”,“型號”的形式表明CPU的準確型號,就像設備樹(DT)最頂層的“compatible”屬性一樣。 稍後將向cpu節點添加更多屬性,但是我們首先需要討論更多的基本概念。

2.4 節點名字(Node Names)

首先,我們需要瞭解命名的規則。每一個節點必須有一個名字,名字的形式必須是“ <name>[@<unit-address>”。<name>是一個簡單的ascii字元串,最大長度為31位元組。通常,節點是根據它所代表的設備來命名。比如,一個3com公司的網路適配器的名字可能會是“ethernet”,而不是“3com509”。如果這個節點描述設備需要一個地址,則包含“<unit-address>”欄位。通常,這個地址是訪問該設備寄存器所需要的首地址。而且會列在node的“reg”屬性里。關於“reg”屬性將在本文後續的內容中介紹。兄弟節點的名字不能相同,但是通常都是<name>欄位相同,而<unit-address>欄位不同( (比如, serial@101f1000 & serial@101f2000).)。可以查閱ePAPR的2.2.1節來瞭解節點命名的全部細節。

2.5 設備(Devices)

系統中的每個設備都由一個設備樹節點表示。下一步是用每個設備的對應的節點填充樹。現在,新的節點將保持為空,直到我們可以討論如何處理地址範圍和irq。
/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";
        };
    };
};
  在上面這個樹中,已經為系統中的每個設備都添加了一個節點,層次結構反映了設備如何連接到系統。比如,外部匯流排上的設備是外部匯流排節點的子節點,i2c設備是i2c匯流排控制器節點的子節點。通常,層級結構表示的是從CPU的角度來看系統的視圖。 這個設備樹還不能使用,是因為它缺少設備之間的連接信息,接下來會添加進來。 需要註意的是:
  • 每一個節點都有一個“compatible”屬性
  • flash節點的“compatible”屬性包含了兩個字元串,下一節將說明為什麼
  • 就像之前提到的,節點名字反映的是設備的種類,而不是代表具體的品牌型號。 請參閱ePAPR規範的2.2.2節,其中列出了已定義的通用節點名。應該儘可能使用這些節點名,而不要發明新的名字。

2.6 理解“compatible”屬性

設備樹中每一個表示設備的節都要有“compatible”屬性。 “compatible”屬性是操作系統用來決定將哪個設備驅動程式綁定到這個設備的關鍵。 “compatible”是一個字元串列表,列表中的第一個字元串以“製造商”,“型號”的形式指定確切的設備。接下來的字元串表示該設備相容的其他設備。例如,Freescale MPC8349片上系統(Soc)有一個串列設備,執行National Semiconductor的 ns16550 寄存器介面。那麼Freescale MPC8349的串列設備的“compatible”屬性就是“ fsl,mpc8349-uart”,“ns16550”.在這個例子里,“ fsl,mpc8349-uart”表示確切的設備,“ns16550”表示它在寄存器級別與National Semiconductor的ns16550串列設備相容。這裡的“ns16550”沒有製造商的名字,是由於歷史原因。所有新的相容性設備名稱,都需要加製造商的名字。這種做法允許將現有設備驅動程式綁定到新設備,同時仍然惟一地標識確切的硬體。 警告:不要使用通配符來實現相容性,比如 "fsl,mpc83xx-uart"或者類似的值。但晶元供應商總是會修改命名規則,一旦等到其改變打破了你的通配符假設,再來修改就已經晚了。所以,請選擇一個具體的晶元型號,然後再相容性列表裡面列出所相容的晶元型號。

3 如何定址(How addressing work)

可定址設備使用以下屬性將地址信息編碼到設備樹中:
* reg
* #address-cells
* #size-cells
每一個可定址設備都有一個叫“reg”的屬性,reg由一系列元組構成,形式是reg = <address1 length1 [address2 length2] [address3 length3] ... >。也就是address、length交替出現。每一個元組代表一個設備使用的地址範圍。每一個地址的值是一個或者多個32位int型數構成的列表,稱為cells。長度的取值也是一個cells列表,或者為空。 由於address和length欄位都是可變大小的變數,因此父節點中的#address-cells和#size-cells屬性用於說明每個欄位中有多少個單元格。換句話說,正確地解釋reg屬性需要父節點的#address-cells和#size-cells值。要瞭解這一切是如何工作的,讓我們將定址屬性添加到示例設備樹中,從cpu開始。#address-cells表示address的長度,#size-cells表示length的長度,如果為0,則表示沒有。

3.1 CPU定址

當講述如何定址的時候,CPU節點是一個最簡單的例子。每個CPU被分配一個唯一的ID,而且這個ID沒有關於size的描述。
    cpus {
        #address-cells = <1>;
        #size-cells = <0>;
        cpu@0 {
            compatible = "arm,cortex-a9";
            reg = <0>;
        };
        cpu@1 {
            compatible = "arm,cortex-a9";
            reg = <1>;
        };
    };
在cpu節點中,將#address-cells設置為1,將#size-cells設置為0。這意味著子reg值是一個uint32數,它是一個沒有size欄位的地址。在這種情況下,為這兩個cpu分配了地址0和1。對於cpu節點,#size-cells為0,因為每個cpu只分配一個地址,沒有其他的地址。 您還會註意到reg值與節點名中的@符號後面的值相同。按照習慣,如果節點具有reg屬性,那麼節點名必須包含單元地址,而且是reg屬性中的第一個地址的值。

3.2 記憶體映射設備

與CPU節點只有一個地址值不同,記憶體映射設備會分配一個它需要響應的地址區間。#size-cells表示reg中length的位寬,如果是32位寬就是1,64位寬就是2.在下麵的示例里,每個address值是1個單元格(32位),每個length也是一個單元格(32位),這在32位操作系統中是非常常見的。在64位系統可能將#address-cells、#size-cells都設置為2,從而完成64位地址空間的定址。
/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 >;
    };
 
    ...
 
};
每一個設備都被分配了一個基地址,以及它被分配區域的大小。在這個例子里,GPIO設備被分配了兩個地址區間,  0x101f3000...0x101f3fff and 0x101f4000..0x101f400f.。 有一些設備掛載的匯流排的定址方式不同。比如,有些設備掛載的匯流排是通過不同的片選信號線來區分設備。 由於每個父節點都為其子節點定義了定址域,因此可以選擇一種最匹配的方式來描述其子節點的定址方式。下麵的代碼顯示了一種掛載到外部匯流排的設備的定址方式,並將片選信號編碼到地址域中。    
 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";
            reg = <2 0 0x4000000>;
        };
    };
 
匯流排“ external-bus”使用2個單元格來表示地址域,一個是片選號,一個是該片選的設備的基地址偏移。“length”欄位仍然是一個單元格,因為只有地址的偏移需要一個範圍。所以在這個例子里,每一個reg包含3個單元格:片選,地址偏移,偏移的範圍。 由於地址域包含在節點及其子節點中, 所以父節點可以自由地定義任何對匯流排有意義的定址方案。設備節點不需要考慮本節點之外的地址域的情況。地址映射必須按照地址域一個一個的進行。

3.3 非記憶體映射設備

有一些設備不是地址映射設備。他們可以有地址範圍,但是不能被CPU直接訪問。相反,父設備的驅動將代替CPU間接的訪問設備。以I2C設備為例,每一個設備分配一個地址,但是沒有長度和地址範圍。看起來就像為CPU分配地址一樣。        
 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>;
            };
        };
 

3.4 ranges(地址轉換)

我們已經討論瞭如何為設備分配地址,但目前這些地址只在設備節點地址域有意義。它還沒有描述如何將這些地址映射到CPU可以使用的地址。 根節點總是以CPU的視角來描述地址空間。根節點的子節點已經使用了CPU的地址域,因此不需要任何顯式映射。例如,serial@101f0000設備被直接分配地址0x101f0000。 一些非根節點的子節點的設備沒有直接使用CPU地址域。 為了獲得記憶體映射地址,設備樹必須指定如何將地址從一個域轉換到另一個域。ranges屬性正是為這一目的而設計的。 下麵就是一個簡單的例子,展示了一個包含ranges屬性的設備樹。
/dts-v1/;
/ {
    compatible = "acme,coyotes-revenge";
    #address-cells = <1>;
    #size-cells = <1>;
    ...
    external-bus {
        #address-cells = <2>
        #size-cells = <1>;
        ranges = <0 0  0x10100000   0x10000     // Chipselect 1, Ethernet
                  1 0  0x10160000   0x10000     // Chipselect 2, i2c controller
                  2 0  0x30000000   0x1000000>; // Chipselect 3, NOR Flash
 
 
        ethernet@0,0 {
            compatible = "smc,smc91c111";
            reg = <0 0 0x1000>;
        };
 
        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>;
            };
        };
 
        flash@2,0 {
            compatible = "samsung,k8f1315ebm", "cfi-flash";
            reg = <2 0 0x4000000>;
        };
    };
};
  ranges是一個地址轉換列表。ranges表的每一項都是一個組元,包含子地址、父地址和子地址空間區域的大小。每一個欄位的大小由子節點的 #address-cells 的值,父節點的 #address-cells 的值,以及子節點的 #size-cells 值決定。 對於我們示例中的外部匯流排,子地址是2個單元格,父地址是1個單元格,子地址大小也是1個單元格。因此,三項ranges翻譯如下:
* Offset 0 from chip select 0 is mapped to address range 0x10100000..0x1010ffff
* Offset 0 from chip select 1 is mapped to address range 0x10160000..0x1016ffff
* Offset 0 from chip select 2 is mapped to address range 0x30000000..0x30ffffff
或者,如果父地址空間和子地址空間相同,則節點可以添加一個空的“ranges”屬性。空“ranges”屬性的存在意味著子地址空間中的地址將1:1映射到父地址空間。 您可能會問,為什麼要使用地址轉換,而所有這些都可以用1:1映射來編寫。 有些匯流排(如PCI)具有完全不同的地址空間,其詳細信息需要暴露給操作系統。其他的DMA引擎需要知道匯流排上的真實地址。有時需要將設備分組,因為它們共用相同的軟體可編程物理地址映射。是否應該使用1:1映射在很大程度上取決於操作系統和具體的硬體設計信息。 您還應該註意到,i2c@1,0節點中沒有ranges屬性。原因在於,與外部匯流排不同,i2c匯流排上的設備不是映射到CPU地址域中的記憶體。相反,CPU通過i2c@1,0設備間接訪問rtc@58設備。缺少範圍屬性意味著設備不能被除其父設備之外的任何設備直接訪問。
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 本文是介紹aws 作為api gateway,用asp.net core用web應用,.net core作為aws lambda function。 ...
  • 導航 1.編譯環境 2.項目配置 1.設置附加包含目錄 2.設置附加庫目錄 3.設置附加依賴項 3.CLR中各種定義 1.介面定義 2.類定義 3.枚舉定義 4.屬性定義 4.CLR中各種使用 1.類的實例化 2.命名空間的使用 5.CLR中數據類型的轉換 1.String ^ 到 QString ...
  • " 【.NET Core項目實戰 統一認證平臺】開篇及目錄索引 " 一、什麼是RPC RPC是“遠程調用( Remote Procedure Call )”的一個名稱的縮寫,並不是任何規範化的協議,也不是大眾都認知的協議標準,我們更多時候使用時都是創建的自定義化(例如Socket,Netty)的消息 ...
  • ...
  • github地址 https://github.com/wangchengqun/ratel 配置文件 前臺頁面 Angular + typescript ng-alain windows服務安裝 ...
  • 一、配置服務說明 1.1、linux系統中的一切都是文件 1.2、配置一個服務就是在修改去配置文件 1.3、要想讓新的配置文件立即生效,需要重啟對應的服務 二、配置網卡 2.1、編輯配置文件 vim /etc/sysconfig/network-scripts/ifcfg-ens33 systemc ...
  • 在啟動調試以及設置斷點之後,就到了我們非常關鍵的一步-查看變數。GDB調試最大的目的之一就是走查代碼,查看運行結果是否符合預期。既然如此,我們就不得不瞭解一些查看各種類型變數的方法,以幫助我們進一步定位問題。 ...
  • "Efficient data transfer through zero copy" "Zero Copy I: User Mode Perspective" 0. 前言 在閱讀RocketMQ的官方文檔時,發現Chapter6.1中關於零拷貝的敘述中有點不理解,因此查閱了相關資料,來解釋文中的說 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...