在platform_device部分有簡單說明描述設備有兩種方法:一種是使用platform_device結構體來指定;另一種是使用設備樹來描述。
本篇筆記我們就來簡單地學習一下設備樹的一些知識。
什么是設備樹
設備樹簡單理解就是描述設備信息(資源)的一棵樹。設備樹(Device Tree)用代碼體現如下:
這些代碼被保存在.dts/dtsi后綴文件中,也即設備樹源文件 DTS(DeviceTree Source)。
這些源文件同我們的C代碼一樣,并不能直接使用的,而是得經過一個編譯過程生成機器可運行的二進制文件,如:
dts文件使用dtc工具編譯生成dtb文件,這個dtb文件就是內核可以使用的文件。例如我們的板子跑起來之后,我們系統使用的設備樹文件就存在目錄/boot下:
Linux為什么會引入設備樹?
在上一個實驗:【Linux筆記】LED驅動實驗(總線設備驅動模型)中我們使用了platform_device結構體來描述led設備(硬件資源)。既然已經有了描述設備的方法了,為什么還要引入設備樹呢?
因為Linux內核中有很多BSP(板級支持包),不同的BSP會包含著不同的描述設備的代碼(.c或.h文件)。
隨著芯片的發展,Linux內核中就包含著越來越多這些描述設備的代碼,導致Linux內核代碼會很臃腫。
這導致Linux之父Linus 大發雷霆:"this whole ARM thing is a f*cking pain in the ass"。
因此引入了設備樹文件,從而可精簡一些臃腫的C代碼。除此之外,.dts編譯生成.dtb文件的過程要比.c編譯生成驅動模塊、加載驅動模塊的過程要簡單很多,也更方便我們進行開發。
設備樹的語法
設備樹源文件也是需要根據一定規則來編寫的,同C語言一樣,也要遵循一些語法規則。下面簡單看一下設備樹的源碼結構及語法。
先看一個設備樹示例:
1、節點格式
label:node-name@unit-address
其中:
label:標號
node-name:節點名字
unit-address:單元地址
label 是標號,可以省略。label 的作用是為了方便地引用 node。比如:
可以使用下面 2 種方法來修改 uart@fe001000 這個 node:
2、屬性格式 簡單地說, properties 就是“name=value”, value 有多種取值方式。示例:
-
一個32位的數據,用尖括號包圍起來,如
interrupts=<170xc>;
-
一個64位數據(使用2個32位數據表示),用尖括號包圍起來,如:
clock-frequency=<0x000000010x00000000>;
-
有結束符的字符串,用雙引號包圍起來,如:
compatible="simple-bus";
-
字節序列,用中括號包圍起來,如:
local-mac-address=[000012345678];//每個byte使用2個16進制數來表示
local-mac-address=[000012345678];//每個byte使用2個16進制數來表示
-
可以是各種值的組合,用逗號隔開,如:
compatible="ns16550","ns8250";
example=<0xf00f000019>,"astrangepropertyformat";
3、一些標準屬性(1) compatible 屬性
“compatible”表示“兼容”,對于某個LED,內核中可能有A、B、C三個驅動都支持它,那可以這樣寫:
led{
compatible=“A”,“B”,“C”;
};
內核啟動時,就會為這個LED按這樣的優先順序為它找到驅動程序:A、B、C。
(2)model 屬性
model屬性與compatible屬性有些類似,但是有差別。compatible屬性是一個字符串列表,表示可以你的硬件兼容A、B、C等驅動;model用來準確地定義這個硬件是什么。
比如根節點中可以這樣寫:
/{
compatible="samsung,smdk2440","samsung,mini2440";
model="jz2440_v3";
};
它表示這個單板,可以兼容內核中的“smdk2440”,也兼容“mini2440”。
從compatible屬性中可以知道它兼容哪些板,但是它到底是什么板?用model屬性來明確。
(3)status 屬性
status 屬性看名字就知道是和設備狀態有關的, status 屬性值也是字符串,字符串是設備的狀態信息,可選的狀態如下所示:
(4)#address-cells 和#size-cells 屬性
格式:
address-cells:address要用多少個32位數來表示;
size-cells:size要用多少個32位數來表示。
比如一段內存,怎么描述它的起始地址和大小?
下例中,address-cells為1,所以reg中用1個數來表示地址,即用0x80000000來表示地址;size-cells為1,所以reg中用1個數來表示大小,即用0x20000000表示大小:
/{
#address-cells=<1>;
#size-cells=<1>;
memory{
reg=<0x800000000x20000000>;
};
};
(5)reg 屬性
reg屬性的值,是一系列的“address size”,用多少個32位的數來表示address和size,由其父節點的# address-cells、#size-cells決定。示例:
/dts-v1/;
/{
#address-cells=<1>;
#size-cells=<1>;
memory{
reg=<0x800000000x20000000>;
};
};
(7)name 屬性
過時了,建議不用。它的值是字符串,用來表示節點的名字。在跟platform_driver匹配時,優先級最低。compatible屬性在匹配過程中,優先級最高。
(8)device_type 屬性
過時了,建議不用。它的值是字符串,用來表示節點的類型。在跟platform_driver匹配時,優先級為中。compatible屬性在匹配過程中,優先級最高。
3、常用的節點(1)根節點
用 / 標識根節點,如:
/dts-v1/;
/{
model="SMDK24440";
compatible="samsung,smdk2440";
#address-cells=<1>;
#size-cells=<1>;
};
(2)CPU節點
一般不需要我們設置,在 dtsi 文件中都定義好了,如:
cpus{
#address-cells=<1>;
#size-cells=<0>;
cpu0:cpu@0{
.......
}
};
(3)memory 節點
芯片廠家不可能事先確定你的板子使用多大的內存,所以 memory 節點需要板廠設置,比如:
memory{
reg=<0x800000000x20000000>;
};
(4)chosen 節點
我們可以通過設備樹文件給內核傳入一些參數,這要在chosen節點中設置bootargs屬性:
chosen{
bootargs="noinitrdroot=/dev/mtdblock4rwinit=/linuxrcconsole=ttySAC0,115200";
};
操作設備樹的函數
Linux 內核給我們提供了一系列的函數來獲取設備樹中的節點或者屬性信息,這一系列的函數都有一個統一的前綴“of_”(“open firmware”即開放固件。),所以在很多資料里面也被叫做 OF 函數。
1、節點相關操作函數 Linux 內核使用 device_node 結構體來描述一個節點,此結構體定義在文件 include/linux/of.h 中,定義如下:
與查找節點有關的 OF 函數有 5 個:
(1) of_find_node_by_name 函數
of_find_node_by_name 函數通過節點名字查找指定的節點,函數原型如下:
structdevice_node*of_find_node_by_name(structdevice_node*from,
constchar*name);
(2) of_find_node_by_type 函數
of_find_node_by_type 函數通過 device_type 屬性查找指定的節點,函數原型如下:
structdevice_node*of_find_node_by_type(structdevice_node*from,constchar*type);
(3) of_find_compatible_node 函數
of_find_compatible_node 函數根據 device_type 和 compatible 這兩個屬性查找指定的節點,函數原型如下:
structdevice_node*of_find_compatible_node(structdevice_node*from,constchar*type,
constchar*compatible);
(4)of_find_matching_node_and_match 函數
of_find_matching_node_and_match 函數通過 of_device_id 匹配表來查找指定的節點,函數原型如下:
structdevice_node*of_find_matching_node_and_match(structdevice_node*from,conststructof_device_id*matches,conststructof_device_id**match);
(5)of_find_node_by_path 函數
of_find_node_by_path 函數通過路徑來查找指定的節點,函數原型如下:
inlinestructdevice_node*of_find_node_by_path(constchar*path);
2、提取屬性值的 OF 函數 Linux 內核中使用結構體 property 表示屬性,此結構體同樣定義在文件 include/linux/of.h 中,內容如下:
Linux 內核也提供了提取屬性值的 OF 函數 :(1) of_find_property 函數
of_find_property 函數用于查找指定的屬性,函數原型如下:
property*of_find_property(conststructdevice_node*np,constchar*name,int*lenp);
(2)of_property_count_elems_of_size 函數
of_property_count_elems_of_size 函數用于獲取屬性中元素的數量,比如 reg 屬性值是一個數組,那么使用此函數可以獲取到這個數組的大小,此函數原型如下:
intof_property_count_elems_of_size(conststructdevice_node*np,constchar*propname,intelem_size);
(3)讀取 u8、 u16、 u32 和 u64 類型的數組數據
(4)讀取 u8、 u16、 u32 和 u64 類型屬性值
(5)of_property_read_string 函數
of_property_read_string 函數用于讀取屬性中字符串值,函數原型如下:
intof_property_read_string(structdevice_node*np,constchar*propname,constchar**out_string)
審核編輯 :李倩
-
Linux
+關注
關注
87文章
11410瀏覽量
212198 -
代碼
+關注
關注
30文章
4874瀏覽量
69932 -
設備樹
+關注
關注
0文章
39瀏覽量
3270
原文標題:整理了一份Linux設備樹基礎知識,建議收藏!
文章出處:【微信號:良許Linux,微信公眾號:良許Linux】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
請問stm32mp257如何修改設備樹并加載驅動?
為什么你的串口總是丟一些特殊字符?

宇樹科技在物聯網方面
嵌入式學習-飛凌嵌入式ElfBoard ELF 1板卡-初識設備樹之設備樹組成和結構
飛凌嵌入式ElfBoard ELF 1板卡-初識設備樹之設備樹組成和結構
“碰一下”支付背后的4G技術
FOC電路學習路上的一些硬件坑

繼電器測試的培訓和學習資源有哪些推薦?
分享一些常見的電路

評論