Linux驅動之裝置樹的基礎知識

山無言發表於2020-09-14

前期知識

  1. 如何編寫一個簡單的Linux驅動(一)——驅動的基本框架
  2. 如何編寫一個簡單的Linux驅動(二)——裝置操作集file_operations
  3. 如何編寫一個簡單的Linux驅動(三)——完善裝置驅動

前言

  在前面的文章中,我們只介紹瞭如何對驅動和裝置節點進行操作,並沒有涉及到對具體硬體裝置的操作。從本篇開始,將介紹對硬體裝置的操作。這裡,我們要引入一個新的概念——裝置樹。
  在學習Linux驅動時,我們一般會用到ARM開發板。ARM開發板的廠商有很多,我們熟知的有正點原子、迅為、友善之臂、天嵌等等。我們可以想象這樣一種場景,每家開發板廠商都自己開發板載裝置的驅動,即使使用同一款處理器,但每款板子的廠商對於板載硬體的定義是不相同的,為了板載硬體能夠正常工作,每家廠商都會根據自己的板載硬體來設計不同於其他廠商的驅動,並將其提交到ARM社群,ARM社群再將它們新增到Linux核心。顯然,隨著使用Linux的裝置越來越多,這些驅動就像是一層層的sh*t一樣,糊在Linux核心上,導致Linux核心越來越臃腫。
  在幾年前,ARM社群真的是這麼做的,這就惹惱了大神Linus,於是Linus就給ARM社群來了套素質N連。於是,ARM社群學習了PowerPC的模式,把裝置從核心中獨立出來,形成裝置樹。

1.什麼是裝置樹

  裝置樹是用來描述板級裝置的檔案,板子上所有的裝置資訊都彙集在這一個檔案中,如圖。

  系統匯流排是裝置樹的主幹;CAN控制器、GPIO控制器等是系統匯流排的分支;GPIOA、CAN1、IIC1是更進一步的分支;GPIOA1、AT24C02、MCP2515就是具體裝置。這樣將裝置按照類別組成一棵樹,就組成了一整棵裝置樹。我們可以在系統的"proc/device-tree"目錄下看到系統的裝置樹資訊。

2.DTS檔案和DTSI檔案

  裝置樹原始檔一般包括兩種,dts檔案和dtsi檔案,dtsi檔案是dts檔案的標頭檔案,此外,dts檔案還可以像C語言那樣包含.h格式的標頭檔案。就像下面這樣。

//這是一個dts檔案
/dts-v1/;	//這條語句必須有
#include "xxx.h"	//像C語言一樣包含.h標頭檔案
#include "xxxx.dtsi"	//包含dtsi標頭檔案
...
...

  需要注意的是,在dts檔案中,檔案開始處的/dts-v1/;語句是必備的。可以看到,dts檔案在包含標頭檔案方面和C語言十分相似,都使用#include
  dtsi檔案一般用來描述較為通用的SOC級別的資訊,比如CPU資訊,外設控制器資訊、主頻資訊等等。而dts檔案則用來描述具象化的外設資訊,例如要把GPIOA1用作按鍵,就需要在dts檔案中進行描述。

3.裝置樹原始檔分析

3.1根節點和普通節點

  /{}; 是根節點,其他的node_name{}; 是普通節點。當某個結點在多個關聯檔案中都出現時,不會產生衝突,出現的後者會對前者作為補充;如果後者與前者有相同的屬性,則後者的屬性會覆蓋掉前者的屬性。
  比如:在dtsi標頭檔案中有對adc的描述

adc: adc@126C0000 {
               compatible = "samsung,exynos-adc-v1";
               reg = <0x126C0000 0x100>;
               interrupt-parent = <&combiner>;
               interrupts = <10 3>;
               clocks = <&clock CLK_TSADC>;
               clock-names = "adc";
               #io-channel-cells = <1>;
               io-channel-ranges;
               samsung,syscon-phandle = <&pmu_system_controller>;
               status = "disabled";	//adc不工作
};

  可以在dts檔案中對adc描述進行追加

&adc {
/*vdd-supply = <&ldo3_reg>;*/
status = "okay";	//覆蓋標頭檔案中的status,使能adc
};

3.2特殊的裝置節點

  1. aliases節點:用於儲存其他節點的別名。
  2. chosen節點:該節點並不是一個真的裝置,它的主要功能是幫助uboot向核心傳遞資料,最主要的引數是bootargs引數。

3.3裝置節點的命名

  裝置節點的命名方式有三種。

  1. node-name{}; ; node-name是結點名稱。
  2. node-name@unit-address{}; :unit-address是裝置地址或暫存器首地址。
  3. label: node-name@unit-address{}; :label是節點標籤,可以使用&label快捷地訪問節點。

3.4裝置樹節點的標準屬性

  1. 根節點的compatible屬性:用於標識裝置樹能否與Linux核心匹配,該屬性值的一半格式為"廠商,板子名稱"
  2. 普通節點的compatible屬性:指相容性。該屬性值的一般格式為"廠商,裝置驅動名"。如果Linux核心中的匹配表中有與compatible屬性中的值相同的值,則該Linux核心可以使用該裝置驅動。當驅動的相容性資訊與裝置樹的compatible屬性匹配後,會執行驅動程式碼裡的probe函式。
  3. status屬性:標識裝置可用(“okay”)還是不可用(“disabled”)。當然也有其他的值。
  4. #address-cells#size-cells屬性:用於標明該如何編寫reg屬性值。#address-cells用於標明reg屬性中address所佔字長數,size-cells用於標明length所佔的字長數。
  5. reg屬性:該屬性的格式一般為reg = <address,length, address,length,…>address表示其實地址,length表示地址長度,一般用於記憶體中(也可以用於其他裝置)。例:
#address-cells = <2>;	//起始地址佔兩個字長
#size-cells = <1>;	//地址長度佔一個字長
reg = <0x400080,0x600040,0x4000>;	//表示0x400080和0x600040是起始地址,地址長度為0x4000

4. 驅動程式如何獲取裝置樹資訊

  Linux核心的"linux/of.h"檔案中提供了一系列以of開頭的函式,其中包含了可以獲取裝置樹資訊的函式。

5.DTS、DTB和DTC

  dts是裝置樹原始檔的一種格式,dtb是裝置樹檔案編譯後形成的二進位制檔案的格式,dtc是用來編譯裝置樹檔案的編譯工具。

相關文章