溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

linux dts的作用是什么

發(fā)布時間:2023-03-14 11:03:09 來源:億速云 閱讀:182 作者:iii 欄目:建站服務器

本文小編為大家詳細介紹“l(fā)inux dts的作用是什么”,內容詳細,步驟清晰,細節(jié)處理妥當,希望這篇“l(fā)inux dts的作用是什么”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學習新知識吧。

在linux中,dts是設備樹源文件,用于描述設備信息的;設備樹技術將設備的硬件資源信息就寫在dts文件中。設備樹源文件dts被編譯成dtb二進制,在bootloader運行時傳遞給操作系統,操作系統對其進行解析展開,從而產生一個硬件設備的拓撲圖,有了這個拓撲圖,在編成過程可以直接通過系統提供的接口獲取到設備樹的節(jié)點和屬性信息。

1、什么是設備樹?

設備樹(dt:device tree)是linux內核采用的參數表示和傳遞技術,在系統引導啟動階段進行設備初始化的時候,將設備樹中描述的硬件信息傳遞給操作系統;

  • dts(device tree source):設備樹源文件,描述設備信息的;

    設備樹源文件dts被編譯成dtb二進制,在bootloader運行時傳遞給操作系統,操作系統對其進行解析展開,從而產生一個硬件設備的拓撲圖,有了這個拓撲圖,在編成過程可以直接通過系統提供的接口獲取到設備樹的節(jié)點和屬性信息

  • dtc(device tree compiler):設備樹編譯/反編譯/調試工具;

  • dtb(device tree binary):二進制設備樹鏡像;

  • dtsi(device tree source include):功能類似設備樹文件的頭文件,可以被dts文件通過include引用,dtsi文件一般是描述共性部分;

2、設備樹解決什么問題

  • 在設備驅動源碼中,分為驅動代碼和設備代碼,驅動代碼是操作硬件的方法,設備代碼是硬件資源、數據,當驅動代碼和設備代碼匹配時就會調用驅動的probe函數,probe函數會利用設備代碼的資源去初始化設備;

  • 設備樹之前,設備代碼都是直接寫在內核源碼中的,以platform_device結構體的形式存在,驅動代碼和設備代碼也是在platform總線上匹配,當需要修改設備資源時,就需要修改內核源碼;

  • 設備樹技術將設備的硬件資源信息就寫在dts文件中,需要修改就修改dts文件,不必在修改內核源碼;

  • 不采用設備樹技術:內核源碼中會充斥大量設備硬件描述信息,導致內核源碼不停增多,但是增多的硬件描述信息代碼和內核功能并不相關;

  • 采用設備樹技術之后:設備的硬件描述信息都在dts文件中,修改方便,但是內核要增加解析dts文件格式的代碼;

3、設備樹怎么工作

linux dts的作用是什么

  • 驅動開發(fā)者根據硬件編寫/修改dts文件,使得將來驅動代碼能匹配到合適的設備硬件信息;

  • 編譯內核時,kernel會先編譯出dtc,然后再用dtc將dts文件編譯成dtb;

  • uboot啟動kernel時,將內核鏡像和dtb都重定位到內存,并告訴內核dtb的所在內存地址;

  • 內核啟動初期調用內部函數解析dtb,得到硬件信息后再組裝成硬件函數,最后去和驅動代碼進行匹配;

4、設備樹源碼dts文件格式講解

4.1、dts文件在內核源碼中的存放位置

arm架構:arch/arm/boot/dts目錄中

4.2、dts文件格式簡介

  • 注釋用/* */,注意#開頭的不是注釋

  • 分號是段落塊之間的分隔符,{}和[]和<>是段落塊的封裝符號,和C語言語言類

  • /dts-v1/節(jié)點,表示dts的版本號,目前都是v1

  • /{}是根節(jié)點root node,理論上只應該有一個根節(jié)點,有說法dtc會合并所有root node為同一個

  • dts是樹狀的多節(jié)點組織,基本單元是node,除root外其他node都有parent,還可以有child

4.3、節(jié)點格式

4.3.1、格式定義

[label:] <node-name> [@<unit-address>]{
  [property]
  [child nodes]
  [child nodes]
  ......
};

4.3.2、格式解讀

  • []:表示該項可以省略,<>:表示不可省略;

    [label:]:label是標簽名,為了方便訪問節(jié)點,后面可以直接通過&label來訪問該節(jié)點。

  • node-name:節(jié)點名稱。根節(jié)點的名稱必須是/

  • [@unit-address]:unit-address是設備地址,如cpu node就是0、1這種,reg node就是0x12010000這種;

4.3.3、示例代碼

cpus {
	/* 下面三項是cpus節(jié)點的屬性 */
	#address-cells = <1>;
	#size-cells = <0>;
	enable-method = "hisilicon,hi3516dv300";

	/* 下面是子節(jié)點 */
	cpu@0 {
		device_type = "cpu";
		compatible = "arm,cortex-a7";
		clock-frequency = <HI3516DV300_FIXED_1000M>;
		reg = <0>;
	};
};

  • cpus是cpu的父節(jié)點,從形式來能直觀的看出來,cpu節(jié)點是被cpus節(jié)點的大括號括起來的;

  • cpus節(jié)點省略了標簽名和設備地址,只有節(jié)點名稱;

5、節(jié)點屬性分析

5.1、GPIO屬性格式

/{
	gpx1:gpx1{
		controller;
		#gpio-cells=<2>;
	};
	
	key@11400c24{
		compatible="fs4412,key";
		reg=<0x11400c24 0x4>;
		intn-key=<&gpx1 2 2>;
	}
}

  • gpio-controller:說明該節(jié)點描述的是一個gpio控制器;

  • #gpio-cells:描述gpio使用節(jié)點的屬性一個cell的內容;

5.2、compatible屬性格式

uart0: uart@120a0000 {
	compatible = "arm,pl011", "arm,primecell";
	reg = <0x120a0000 0x1000>;
	interrupts = <0 6 4>;
	clocks = <&clock HI3516DV300_UART0_CLK>;
	clock-names = "apb_pclk";
	status = "disabled";
};

/* 在驅動中對應的結構體*/

//struct device_driver->of_match_table->compatible

struct of_device_id {
	char	name[32];
	char	type[32];
	char	compatible[128];
	const void *data;
};

(1)compatible屬性是用于設備節(jié)點和設備驅動匹配用的,在內核描述驅動的structdevice_driver結構體中,compatible變量中就會保存用于匹配的字符串,當設備節(jié)點和驅動的

compatible相同時就匹配成功;

(2)compatible后面可以有多個字符串,優(yōu)先匹配靠前的字符串,靠前的字符串匹配不上才會匹配后面的字符串;

5.3、model屬性格式

/ {
	model = "Tyr DEMO Board";
	compatible = "hisilicon,hi3516dv300";

	memory {
		device_type = "memory";
		reg = <0x82000000 0x20000000>;
	};};

(1)model是描述模塊信息的,一般只有根節(jié)點才有,標明設備樹文件對應的開發(fā)板的名稱;

(2)在內核的啟動打印中可以看到model的值:“OF: fdt:Machine model: Tyr DEMO Board”;

5.4、status屬性格式

&uart0 {
	status = "okay";
};

狀態(tài)值含義
okey表示設備是可操作的
disabled表示當前不可操作,但是后續(xù)是可以更改為可操作性的
fail、failed表示有嚴重錯誤,幾乎不可能再可操作了

(1)status描述設備信息狀態(tài),在設備樹文件中可以根據需求設置模塊的狀態(tài),功能就是開啟/關閉某個模塊;

(2)在dtsi文件中,默認都是關閉模塊的,在開發(fā)板對應的dts文件中自己去打開需要的模塊;

5.5、reg屬性格式

clock: clock@12010000 {
	compatible = "hisilicon,hi3516dv300-clock";
	#address-cells = <1>;	/* 表示reg里面的數據address占用一個字長*/
	#size-cells = <1>;		/* 表示reg里面的數據size占用一個字長,注意字長不是字節(jié)*/
	#clock-cells = <1>;
	#reset-cells = <2>;
	reg = <0x12010000 0x1000>;	/*起始地址是0x12010000,長度是0x1000*/
};

  • reg屬性:配置某個硬件模塊對應的地址范圍信息;

  • #address-cells屬性:表示reg里面的數據address占用的字長,注意字長不是字節(jié);

  • #size-cells:表示reg里面的數據size占用的字長,注意字長不是字節(jié);

  • reg = <address1 length2 address2 length3 …>:address一般用來表示起始地址,length一般表示持續(xù)長度;

5.6、中斷屬性格式

gic: interrupt-controller@10300000 {
	compatible = "arm,cortex-a7-gic";
	#interrupt-cells = <3>;	/*表示interrupts用三個cell來描述中斷*/
	#address-cells = <0>;
	interrupt-controller;	/*標明gic節(jié)點是中斷控制器*/
	/* gic dist base, gic cpu base , no virtual support */
	reg = <0x10301000 0x1000>, <0x10302000 0x100>;
 };
	
ipcm: ipcm@045E0000 {
	compatible = "hisilicon,ipcm-interrupt";
	interrupt-parent = <&gic>;	/*父節(jié)點是gic節(jié)點*/
	interrupts = <0 10 4>;	/*<中斷域 中斷 觸發(fā)方式>*/
	reg = <0x10300000 0x4000>;	
	status = "okay";
};

(1)interrupt-controller:無值屬性,表示這是個中斷控制器node
(2)#interrupt-cells:這是中斷控制器節(jié)點的屬性,用來標識這個控制器需要幾個cell做中斷描述符
(3)interrupt-parent:標識此設備節(jié)點屬于哪一個中斷控制器,如果沒有這個屬性,會自動依附父節(jié)點
(4)interrupts :一個中斷標識符列表,表示每一個中斷輸出信號

6、特殊節(jié)點

6.1、chosen子節(jié)點

6.1.1、chosen子節(jié)點功能介紹

chosen {
	stdout-path = "serial0:115200n8";
};

(1)chosen子節(jié)點不對應真實的設備,是用來描述內核啟動參數的,對應于uboot啟動內核時傳遞的bootargs參數;
(2)上面是摘抄的內核dts文件中的chosen子節(jié)點,里面只設置了stdout-path屬性,也就是把輸出設置成串口0,波特率是115200;
(3)dts文件中設置的屬性會被覆蓋點,具體就是uboot在啟動內核時,會將bootargs啟動參數轉換成chosen子節(jié)點的屬性,替換掉dts文件中設置的屬性;

6.1.2、chosen子節(jié)點在內核中的體現

~ # ls /proc/device-tree/chosen/
bootargs  name
~ # 
~ # cat /proc/device-tree/chosen/bootargs 
mem=1408M console=ttyS0,115200 root=/dev/mmcblk0p7 rootfstype=squashfs rootwait
~ # 
~ # cat /proc/device-tree/chosen/name 
chosen
~ #

6.2、aliases子節(jié)點

	aliases {
		serial0 = &uart0;
		gpio0 = &gpio_chip0;
		gpio1 = &gpio_chip1;
		gpio2 = &gpio_chip2;
		······	
	};

aliases就是別名的意思,aliases節(jié)點主要功能就是給節(jié)點定義別名,為了方便訪問節(jié)點。不過我們在節(jié)點命名的時候可以加上label標簽,直接通過&label引用標簽來訪問也很方便,aliases節(jié)點內部其實也是通過引用標簽名來定義別名;

7、節(jié)點相關操作

7.1、節(jié)點引用和內容替換

gpio_chip1: gpio_chip@120d1000 {
	compatible = "arm,pl061", "arm,primecell";
	reg = <0x120d1000 0x1000>;
	interrupts = <0 17 4>;
	clocks = <&clock  HI3516DV300_SYSAPB_CLK>;
	clock-names = "apb_pclk";
	#gpio-cells = <2>;
	status = "disabled";
};

/*引用gpio_chip1節(jié)點*/
&gpio_chip1 {
	status = "okay";	/*替換status屬性內容*/
};

對于已經定義好的節(jié)點,我們通過引用節(jié)點的方式,重新定義某些屬性,效果上看就是替換掉某些屬性的值;

7.2、合并節(jié)點內容

/{
	node{
		key1=value1;
	}
}

/{
	node{
		key2=value2;
	}
}

//合并的結果
/{
	node{
		key1=value1;
		key2=value2;
	}
}

有時候我們需要增加硬件描述的信息,這時候就可以在后面創(chuàng)新定義該節(jié)點,最后解析的時候會把同名節(jié)點不同的部分進行合并。

讀到這里,這篇“l(fā)inux dts的作用是什么”文章已經介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內容的文章,歡迎關注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI