Linux裝置樹詳解
裝置樹詳解
在Linux3.x版本後,arch/arm/plat-xxx和arch/arm/mach-xxx中,描述板級細節的程式碼(比如platform_device、i2c_board_info等)被大量取消,取而代之的是裝置樹,其目錄位於arch/arm/boot/dts
1.裝置樹的組成
1個dts檔案+n個dtsi檔案,它們編譯而成的dtb檔案就是真正的裝置樹
- soc廠商會把soc公共的特性和多塊開發板公用的特性提煉為dtsi,而dts則負責描述某個具體的產品(開發板)的特性。dts直接或間接的包含多個dtsi(類似於c語言的標頭檔案),就體現了一個完整的產品(開發板)所有的特性。以solidrun公司的hummingboard為例,其組成為
imx6dl-hummingboard.dts
|_imx6dl.dtsi
| |_imx6qdl.dtsi
|_imx6qdl-microsom.dtsi
|_imx6qdl-microsom-ar8035.dtsi
- 此外,dts/dtsi相容c語言的一些語法,能使用巨集定義,也能包含.h檔案
2.裝置樹的結構
下面分別是是imx6dl-hummingboard.dts以及imx6dl.dtsi檔案,我們以它們為例來分析,不難發現dts檔案內容很少,只有一些板級的特徵,大部分公共的硬體描述都在dtsi檔案中
- imx6dl-hummingboard.dts 檔案節選
/dts-v1/;
#include "imx6dl.dtsi"
#include "imx6qdl-microsom.dtsi"
#include "imx6qdl-microsom-ar8035.dtsi"
/ {
model = "SolidRun HummingBoard DL/Solo";
compatible = "solidrun,hummingboard", "fsl,imx6dl";
ir_recv: ir-receiver {
compatible = "gpio-ir-receiver";
gpios = <& gpio1 2 1>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_hummingboard_gpio1_2>;
};
regulators {
compatible = "simple-bus";
reg_3p3v: 3p3v {
compatible = "regulator-fixed";
regulator-name = "3P3V";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
};
}
&i2c1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_hummingboard_i2c1>;
rtc: [email protected]68 {
compatible = "nxp,pcf8523";
reg = <0x68>;
};
};
- imx6dl.dtsi檔案節選
/ {
aliases {
/*省略無關程式碼*/
}
soc {
#address-cells = <1>;
#size-cells = <1>;
compatible = "simple-bus";
interrupt-parent = <&intc>;
ranges;
/*省略無關程式碼*/
[email protected]00a00600 {
compatible = "arm,cortex-a9-twd-timer";
reg = <0x00a00600 0x20>;
interrupts = <1 13 0xf01>;
clocks = <&clks IMX6QDL_CLK_TWD>;
};
aips-bus@02000000 { /* AIPS1 */
compatible = "fsl,aips-bus", "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
reg = <0x02000000 0x100000>;
ranges;
/*省略無關程式碼*/
gpio1: [email protected]0209c000 {
compatible = "fsl,imx6q-gpio", "fsl,imx35-gpio";
reg = <0x0209c000 0x4000>;
interrupts = <0 66 IRQ_TYPE_LEVEL_HIGH>,
<0 67 IRQ_TYPE_LEVEL_HIGH>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
};
/*省略無關程式碼*/
i2c1: [email protected]021a0000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl,imx6q-i2c", "fsl,imx21-i2c";
reg = <0x021a0000 0x4000>;
interrupts = <0 36 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX6QDL_CLK_I2C1>;
status = "disabled";
};
};
/*省略無關程式碼*/
};
};
基本構造
- {}包圍起來的結構稱之為節點,dts中最開頭的
/ {}
,稱為根節點。節點的標準結構是[email protected]{…},xxx是節點的名字,yyy則不是必須的,其值為節點的地址(暫存器地址或其他地址),比如i2c1: [email protected]
中的就是一個i2c控制器的暫存器基地址,rtc: [email protected]
中的就是這個rtc裝置的i2c地址
屬性:地址
- 有關節點的地址,比如
[email protected]
,雖然它在名字後面跟了地址,但是正式的設定是在reg屬性中設定的比如:reg = <0x021a0000 0x4000>;
reg的格式通常為<address length>
,0x021a0000是暫存器基地址,0x4000是長度。address 和length的個數是可變的,由父節點的屬性#address-cells
和#size-cells
決定,比如節點[email protected]
的父節點是[email protected]
,其#address-cells
和#size-cells
均為1,所以下面的i2c節點的reg屬性就有一個address 和length,而i2c節點本身#address-cells
和#size-cells
分別為1和0,所以其下的rtc: [email protected]
的reg屬性就只有一個0x68(i2c地址)了
屬性:相容性
- 如果一個節點是裝置節點,那麼它一定要有compatible(相容性),因為這將作為驅動和裝置(裝置節點)的匹配依據,compatible(相容性)的值可以有不止一個字串以滿足不同的需求,詳見下一節。而根節點的compatible也是非常重要的,也就是
"fsl,imx6dl"
這個字串,因為系統啟動後,將根據根節點的compatible來判斷cpu資訊,並由此進行初始化
屬性設定的套路
- 一般來說,每一種裝置的節點屬性設定都會有一些套路,比如可以設定哪些屬性?屬性值怎麼設定?那怎麼知道這些套路呢,有兩種思路
- 第一種是抄類似的dts,比如我們自己專案的平臺是4412,那麼就可以抄exynos4412-tiny4412.dts、exynos4412-smdk4412.dts這類相近的dts
- 第二種是查詢核心中的文件,比如
Documentation/devicetree/bindings/i2c/i2c-imx.txt
就描述了imx平臺的i2c屬性設定方法;Documentation/devicetree/bindings/fb
就描述了lcd、lvds這類屬性設定方法
節點之間的聯絡
- 節點與節點之間的關聯,通常通過“標號引用”和“包含”來實現
- 所謂標號引用,就是在節點名稱前加上標號,這樣裝置樹的其他位置就能夠通過&符號來呼叫/訪問該節點,比如上面程式碼ir_recv節點中的gpio屬性,就引用了gpio1標號處的節點
- 包含則是最基本的方式,比如我們要在i2c1介面新增一個i2c外設,那麼就必須要在i2c1下面新增一個節點,比如上面程式碼中的
rtc: [email protected] {}
- 標號引用常常還作為節點的重寫方式,比如下面程式碼是imx6qdl.dtsi中定義的i2c節點,而前面imx6dl-hummingboard.dts中的&i2c1,就是對i2c1標號處節點的一次重寫,在其內部添加了一個rtc裝置
- 如果一個節點是屬性節點(即僅僅是作為屬性被其他節點呼叫),那麼它定義在哪裡其實無所謂,重要的是呼叫的位置,比如lcd螢幕的時序,其實我們完全可以把它定義在其他犄角旮旯,然後在lcd節點下用&來呼叫它,這也是可以的。這有點類似於函式:在哪定義不重要,重要的是在哪呼叫
3.核心(驅動)與節點的匹配
首先,核心必須要知道dtb檔案的地址,這由U-boot來告訴核心,詳見U-boot引導核心流程分析 第6節。只要核心知曉了dtb檔案的地址,那麼驅動就可以通過一些API任意獲取裝置樹的內部資訊
- 對於3.x版本之後的核心,platform、i2c、spi等裝置不再需要在mach-xxx中註冊,驅動程式將直接和裝置樹裡的裝置節點進行配對,是通過裝置節點中的compatible(相容性)來與裝置節點進行配對的,這裡只做簡單介紹,具體的應用詳見 基於i2c子系統的驅動分析、 基於platform匯流排的驅動分析
- 這裡以pcf8523驅動為例,只要驅動中的of_match_table 中的compatible 值和裝置節點中的compatible 相匹配,那麼probe函式就會被觸發。不僅i2c是這樣,platform、spi等都是這個原理
/*定義的of_match_table*/
static const struct of_device_id pcf8523_of_match[] = {
{ .compatible = "nxp,pcf8523" },
{ }
};
/*driver 結構體中的of_match_table*/
static struct i2c_driver pcf8523_driver = {
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(pcf8523_of_match),
},
.probe = pcf8523_probe,
.id_table = pcf8523_id,
};
- i2c和spi驅動還支援一種“別名匹配”的機制,就以pcf8523為例,假設某程式設計師在裝置樹中的pcf8523裝置節點中寫了
compatible = "pcf8523";
,顯然相對於驅動id_table中的"nxp,pcf8523"
,他遺漏了nxp欄位,但是驅動卻仍然可以匹配上,因為別名匹配對compatible中字串裡第二個欄位敏感
4.常見屬性的設定與獲取
當修改或編寫驅動時,常常需要修改gpio、時鐘、中斷等等引數,以前都是在mach-xxx中的device設定的,現在則要在節點裡設定,然後驅動用特殊的API來獲取
- 屬性的獲取常常在probe函式中進行,但是獲取屬性之前,最重要的是,確定哪個節點觸發了驅動。如果一個驅動對應多個節點,那驅動可以通過
int of_device_is_compatible(const struct device_node *device, const char *name)
來判斷當前節點是否包含指定的compatible(相容性)
gpio的設定與獲取
/*imx6dl.dtsi中gpio1控制器的定義節點*/
gpio1: [email protected]0209c000 {
compatible = "fsl,imx6q-gpio", "fsl,imx35-gpio";
reg = <0x0209c000 0x4000>;
interrupts = <0 66 IRQ_TYPE_LEVEL_HIGH>,
<0 67 IRQ_TYPE_LEVEL_HIGH>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
};
/*imx6qdl-sabreauto.dtsi中某個裝置節點*/
max7310_reset: max7310-reset {
compatible = "gpio-reset";
reset-gpios = <&gpio1 15 1>;
reset-delay-us = <1>;
#reset-cells = <0>;
};
一般來說,我們把gpio屬性的名字起為xxx-gpios
(xxx我們可以隨便起),這樣驅動才能通過特定API從識別該屬性,並轉換成具體的gpio號- 該裝置節點中設定了
reset-gpios = <&gpio1 15 1>;
這格式是什麼意思呢?&gpio1 15
引用了gpio1節點,故此處含義為gpio1_15這個引腳;最後一個引數1則代表低電平有效,0則為高電平有效。至於gpio1_15具體對應哪個引腳,在imx6的手冊上都有詳細描述 - 其實最後一個引數(高低電平有效)不是必須的,因為gpio1節點中設定了
#gpio-cells = <2>;
,所以才有兩個引數;某些soc的gpio節點中會設定為#gpio-cells = <1>;
,那麼可以不寫最後一個引數 - 驅動一般通過以下介面獲取上面節點中gpio的屬性。該函式第一個引數是節點,一般可以在傳入probe的引數中間接獲得;第二個引數是gpio屬性的名字,一定要和節點屬性中的
xxx-gpios
相同;最後一個是編號index,當節點中有n個同名的xxx-gpios時,可以通過它來獲取特定的那個gpio,同一節點中gpio同名情況很少存在,所以我們都把index設為0
gpio = of_get_named_gpio(node, "reset-gpios", index);
- 在dts和驅動都不關心gpio名字的情況下,也可直接通過以下介面來獲取gpio號,這個時候編號index就十分重要了,可以指定拿取節點的第index個gpio屬性
gpio = of_get_gpio(node, index);
中斷的設定與獲取
假設某裝置節點需要一個gpio中斷
/*先確定中斷所在的組*/
interrupt-parent = <&gpio6>;
/*表示中斷,GPIO6中的第8個IO,2為觸發型別,下降沿觸發*/
interrupts = <8 2>;
- 而在驅動中使用
中斷號 =irq_of_parse_and_map(node, index)
函式返回值來得到中斷號
自定義屬性的設定與獲取
所謂的自定義屬性,有點類似於老核心中的platform_data,我們在裝置節點中可以隨意新增自定義屬性,比如下面這個節點裡面的屬性都是我們自己定義的
reg_3p3v: 3p3v {
compatible = "regulator-fixed";
regulator-name = "3P3V";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
};
- 針對32位整形的屬性,比如上面的regulator-min-microvolt,可以利用下面這個API來獲取屬性值,第一個引數是節點,第二個引數是屬性名字,第三個是輸出型引數(把讀出來的值放進去)
of_property_read_u32(node, "regulator-min-microvolt", µvolt);
- 類似的讀取數值的API還有:
int of_property_read_u8(const struct device_node *np, const char *propname, u8 *out_value)
int of_property_read_u16(const struct device_node *np, const char *propname, u16 *out_value)
- 下列API可檢查節點中某個屬性是否存在,存在則返回true,不存在則返回false
bool of_property_read_bool(const struct device_node *np, const char *propname)
- 當節點中存在字串時,可以像下面那樣讀取,比如我們讀取前面reg_3p3v節點中的字串
of_property_read_string(node, "regulator-name", &string)
- 當節點中存在陣列時,可以像下面那樣讀取
/*帶有陣列的某個節點*/
L2: cache-controller@1e00a000 {
compatible = "arm,pl310-cache";
arm,data-latency = <1 1 1>;
arm,tag-latency = <1 1 1>;
};
/*驅動中使用API來讀取陣列, &data為輸出型引數*/
of_property_read_u32_array(node, "arm,pl310-cache", &data, ARRAY_SIZE(data));
相關推薦
linux裝置樹詳解-韋東山-專題視訊課程
linux裝置樹詳解—150人已學習 課程介紹 現在的linux核心(Linux3.X)都已支援裝置樹機制(dts),不管你是玩核心還是玩驅動,一定會碰到裝置樹,而網上雖然有很多部落格,但都講的不夠清晰,看了還是不懂,半桶水,學員急需一套講解裝置樹比較透徹的課程
Linux裝置樹詳解
裝置樹詳解在Linux3.x版本後,arch/arm/plat-xxx和arch/arm/mach-xxx中,描述板級細節的程式碼(比如platform_device、i2c_board_info等)被大量取消,取而代之的是裝置樹,其目錄位於arch/arm/boot/dts
Linux 裝置樹詳解
本文基於天嵌E9V3開發板,詳解裝置樹的規則和用法。 一、基本概念 DTS即Device Tree Source,是一個文字形式的檔案,用於描述硬體資訊,包括CPU的數量和類別、記憶體基地址和大小、中斷控制器、匯流排和橋、外設、時鐘和GPIO控制器等。 DTB即
Linux DTS(Device Tree Source)裝置樹詳解
一.什麼是DTS?為什麼要引入DTS? DTS即Device Tree Source 裝置樹原始碼, Device Tree是一種描述硬體的資料結構,它起源於 OpenFirmware (OF)。 在Linux 2.6中,ARM架構的板極硬體細節過多地被硬編碼在arc
Linux DTS(Device Tree Source)裝置樹詳解之一(背景基礎知識篇)
本系列導航: 一.什麼是DTS?為什麼要引入DTS? DTS即Device Tree Source 裝置樹原始碼, Device Tree是一種描述硬體的資料結構,它起源於 OpenFirmware (OF)。 在Linux 2.6中,ARM架構的板極硬體細節過
Linux DTS(Device Tree Source)裝置樹詳解之二(dts匹配及發揮作用的流程篇)
本系列導航: 有上一篇文章,我們瞭解了dts的背景知識和相關基礎,這次我們對應實際裝置進行一下相關分析。 DTS裝置樹的匹配過程 一個dts檔案確定一個專案,多個專案可以包含同一個dtsi檔案。找到該專案對應的dts檔案即找到了該裝置樹的根節點。 kernel
高通平臺msm8953 Linux DTS(Device Tree Source)裝置樹詳解之二(DTS裝置樹匹配過程)
本系列導航:有上一篇文章,我們瞭解了dts的背景知識和相關基礎,這次我們對應實際裝置進行一下相關分析。DTS裝置樹的匹配過程一個dts檔案確定一個專案,多個專案可以包含同一個dtsi檔案。找到該專案對應的dts檔案即找到了該裝置樹的根節點。kernel\arch\arm\bo
裝置樹詳解
轉載地址:http://blog.csdn.net/qq_28992301/article/details/53321610在Linux3.x版本後,arch/arm/plat-xxx和arch/arm/mach-xxx中,描述板級細節的程式碼(比如platform_devi
裝置樹詳解 (借點引用, &... , 結構, 節點屬性設定如gpio的上拉,下拉,io中斷設定等 )
轉載於 : http://blog.csdn.net/qq_28992301/article/details/53321610 在Linux3.x版本後,arch/arm/plat-xxx和arch/arm/mach-xxx中,描述板級細節的程式碼(比如platform
Linux裝置樹語法詳解【轉】
轉自:https://www.cnblogs.com/xiaojiang1025/p/6131381.html 概念 Linux核心從3.x開始引入裝置樹的概念,用於實現驅動程式碼與裝置資訊相分離。在裝置樹出現以前,所有關於裝置的具體資訊都要寫在驅動裡,一旦外圍裝置變化,驅動程式碼就要重寫。引入了裝置樹之
Linux裝置樹語法詳解
概念 Linux核心從3.x開始引入裝置樹的概念,用於實現驅動程式碼與裝置資訊相分離。在裝置樹出現以前,所有關於裝置的具體資訊都要寫在驅動裡,一旦外圍裝置變化,驅動程式碼就要重寫。引入了裝置樹之後,驅動程式碼只負責處理驅動的邏輯,而關於裝置的具體資訊存放到裝置樹檔案中,
【Linux驅動】Linux裝置樹語法詳解
1 概念Linux核心從3.x開始引入裝置樹的概念,用於實現驅動程式碼與裝置資訊相分離。在裝置樹出現以前,所有關於裝置的具體資訊都要寫在驅動裡,一旦外圍裝置變化,驅動程式碼就要重寫。引入了裝置樹之後,驅動程式碼只負責處理驅動的邏輯,而關於裝置的具體資訊存放到裝置樹檔案中,這樣,如果只是硬體介面資訊的變化而沒有
linux裝置樹dts移植詳解
摘 要:裝置樹的引入減少了核心為支援新硬體而需要的改變,提高程式碼重用,加速了Linux支援包的開發,使得單個核心映象能支援多個系統。作為U-Boot 和Linux 核心之間的動態介面,本文闡述了裝置樹的資料儲存格式以及原始碼描述語法,進而分析了U-Boot 對扁平設備樹的
linux裝置樹dts一之移植詳解
支援包的開發,使得單個核心映象能支援多個系統。作為U-Boot 和Linux 核心之間的動態 介面,本文闡述了裝置樹的資料儲存格式以及原始碼描述語法,進而分析了U-Boot 對扁平設 備樹的支援設定,Linux 核心對裝置樹的解析流程。 關鍵詞:扁平裝置樹; DTS; PowerPC; Linux IBM、S
《Linux4.0裝置驅動開發詳解》筆記--第十八章:ARM Linux裝置樹
18.1 ARM裝置樹簡介 裝置舒適一種描述印鑑的資料結構,它起源於OpenFirmware(OF) 採用裝置樹前後對比: 採用裝置樹之前:ARM架構的板極硬體細節過多的被硬編碼在arch/arm/plat-xxx和arch/arm/mach-xxx中
Linux塊裝置驅動詳解(一)
請求佇列跟蹤等候的塊I/O請求,它儲存用於描述這個裝置能夠支援的請求的型別資訊、它們的最大大小、多少不同的段可進入一個請求、硬體扇區大小、對齊要求等引數,其結果是:如果請求佇列被配置正確了,它不會交給該裝置一個不能處理的請求。 請求佇列還實現一個插入介面,這個介面允許使用多個I/O排程器,I/
《Linux驅動開發詳解》——LCD裝置驅動重要資料結構及驅動框架
核心檔案:/drivers/video/fbmem.c 18.2.3.Linux幀緩衝相關資料結構與函式 1. fb_info結構體(最關鍵) /* struct fb_info 結構體 */ struct fb_info { int node;
Linux啟動流程詳解
linux 詳解 啟動流程 grub mbr 內核 linux啟動流程第一部分 Linux啟動基礎知識1.1 linux centos6.8啟動流程圖 BIOS加電自檢à加載MBRà加載啟動grubà加載內核à啟動/sbin/i
Linux netstat命令詳解,高級面試必備
bytes tool head osi ngs 進行 pen 通信 詳細信息 簡介 Netstat 命令用於顯示各種網絡相關信息,如網絡連接,路由表,接口狀態 (Interface Statistics),masquerade 連接,多播成員 (Multicast Mem
linux top 命令詳解
ctrl+ 一次 所有 使用方法 ase 隱藏 統計 ini 前臺 top命令是Linux下常用的性能分析工具,能夠實時顯示系統中各個進程的資源占用狀況,類似於Windows的任務管理器。下面詳細介紹它的使用方法。top - 01:06:48 up 1:22, 1 user