ホームページ >運用・保守 >Linuxの運用と保守 >Linux dtsの用途は何ですか

Linux dtsの用途は何ですか

青灯夜游
青灯夜游オリジナル
2023-03-14 10:34:081564ブラウズ

Linux では、dts はデバイス情報を記述するために使用されるデバイス ツリー ソース ファイルであり、デバイス ツリー テクノロジによってデバイスのハードウェア リソース情報が dts ファイルに書き込まれます。デバイス ツリー ソース ファイル dts は dtb バイナリにコンパイルされ、ブートローダーの実行時にオペレーティング システムに渡されます。オペレーティング システムはそれを解析および展開して、ハードウェア デバイスのトポロジ図を生成します。このトポロジ図を使用して、コンパイル プロセスで次のことができます。システムが提供するインターフェースを介して、デバイスツリーのノードおよび属性情報を取得します。

Linux dtsの用途は何ですか

#このチュートリアルの動作環境: linux7.3 システム、Dell G3 コンピューター。

1. デバイス ツリーとは何ですか?

デバイス ツリー (dt: デバイス ツリー) は、Linux カーネルで使用されるパラメータ表現および転送テクノロジです。システムのブート フェーズでのデバイスの初期化中に、デバイス ツリーに記述されたハードウェア情報がデバイス ツリーに転送されます。オペレーション システム;

  • dts (デバイス ツリー ソース): デバイス情報を記述するデバイス ツリー ソース ファイル;

    デバイス ツリー ソース ファイル dts は、dtb バイナリにコンパイルされます。ブートローダー それは実行時にオペレーティング システムに渡され、オペレーティング システムはこれを解析および展開してハードウェア デバイスのトポロジ図を生成します。このトポロジ図では、デバイス ツリーのノードおよび属性情報を、ブートローダを通じて直接取得できます。コンパイル プロセス中にシステムによって提供されるインターフェイス

  • dtc(デバイス ツリー コンパイラ): デバイス ツリーのコンパイル/逆コンパイル/デバッグ ツール;

  • dtb(デバイス ツリー バイナリ) : バイナリ デバイス ツリー イメージ;

  • dtsi (デバイス ツリー ソース インクルード): デバイス ツリー ファイルと同様に機能し、以下から参照できるヘッダ ファイルインクルードによる dts ファイル。dtsi ファイルは通常、共通部分を記述します。

#2. デバイス ツリーはどのような問題を解決しますか?

  • デバイスドライバーのソースコードは、ハードウェアの動作方法であるドライバーコードと、ハードウェアのリソースやデータであるデバイスコードに分かれています。ドライバー コードとデバイス コードが一致すると、ドライバーのプローブ関数が呼び出されます。プローブ関数は、デバイス コードのリソースを使用して初期化します。デバイス;

  • デバイス ツリーの前に、デバイス コードはカーネル ソース コードに直接書き込まれ、platform_device 構造体の形式で存在しました。ドライバー コードとデバイス コードもプラットフォーム バス上で一致しました。デバイス リソースを変更する必要がある場合は、カーネル ソースを変更する必要があります。 code;

  • デバイスツリー技術は、デバイスのハードウェアリソース情報をdtsファイルに書き込みますので、変更が必要な場合はdtsファイルを変更してください。カーネルの変更は必要ありません。ソース コード;

  • デバイス ツリー テクノロジを使用しない: カーネル ソース コードには大量のデバイス ハードウェア記述情報が詰め込まれるため、カーネル ソース コードは増加し続けますが、ハードウェア記述情報コードとカーネル関数の増加 関連なし;

  • デバイス ツリー テクノロジを使用した後: デバイスのハードウェア記述情報は dts ファイル内にあり、変更は簡単ですが、カーネルは、dts ファイル形式を解析するコードを追加する必要があります。

3. デバイス ツリーはどのように機能しますか?

Linux dtsの用途は何ですか

  • #ドライバー開発 または、将来ドライバー コードが適切なデバイス ハードウェア情報と一致できるように、ハードウェアに応じて dts ファイルを作成/変更します。

  • カーネルをコンパイルするとき、カーネルは最初に dtc をコンパイルし、次にその dtc を使用して dts ファイルが dtb にコンパイルされます;

  • uboot が開始されるときカーネルを起動すると、カーネル イメージと dtb をメモリに再配置し、dtb のメモリ アドレスをカーネルに伝えます。

  • カーネル起動の初期段階で、内部関数が呼び出されます。 dtb を解析し、ハードウェア情報を取得した後、ハードウェア関数に組み立て、最終的にドライバー コード (

4) と照合します。デバイスツリーソースコードのdtsファイル形式の説明

##4.1. カーネルソースコードにおけるdtsファイルの格納場所

arm アーキテクチャ: Arch/arm/boot/dts ディレクトリ内

##4.2、dts の概要ファイル形式

    コメントには /* */ を使用します。# で始まるものはコメントではないことに注意してください。
  • # #セミコロンは段落ブロック間の区切りです。記号、{}、[]、 は段落ブロックのカプセル化記号であり、C 言語クラス
  • /dts -v1/ ノードは dt のバージョン番号を表します。現在はすべて v1
  • /{} がルート ノードです。理論的には、ルート ノードは 1 つだけあるはずです。その dtc はすべてのルート ノードを同じ
  • dts はツリー状のマルチノード構成です。基本単位はノードです。ルートを除く他のノードには親があり、また、子がいる

4.3. ノードの形式

## 4.3.1. フォーマット定義

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

4.3.2. フォーマット解釈

[]: を示します。 : 省略できないことを示します;
  • [label:]: label はラベル名です。ノードへのアクセスを容易にするために、ノードにアクセスできます。後で &label を使用して直接実行します。

  • node-name:节点名称。根节点的名称必须是/

  • [@unit-address]:unit-address是设备地址,如cpu node就是0、1这种,reg node就是0x12010000这种;

4.3.3、示例代码

cpus {
	/* 下面三项是cpus节点的属性 */
	#address-cells = <1>;
	#size-cells = <0>;
	enable-method = "hisilicon,hi3516dv300";

	/* 下面是子节点 */
	cpu@0 {
		device_type = "cpu";
		compatible = "arm,cortex-a7";
		clock-frequency = <HI3516DV300_FIXED_1000M>;
		reg = <0>;
	};
};
  • cpus是cpu的父节点,从形式来能直观的看出来,cpu节点是被cpus节点的大括号括起来的;

  • cpus节点省略了标签名和设备地址,只有节点名称;

5、节点属性分析

5.1、GPIO属性格式

/{
	gpx1:gpx1{
		controller;
		#gpio-cells=<2>;
	};
	
	key@11400c24{
		compatible="fs4412,key";
		reg=<0x11400c24 0x4>;
		intn-key=<&gpx1 2 2>;
	}
}
  • gpio-controller:说明该节点描述的是一个gpio控制器;

  • #gpio-cells:描述gpio使用节点的属性一个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属性是用于设备节点和设备驱动匹配用的,在内核描述驱动的structdevice_driver结构体中,compatible变量中就会保存用于匹配的字符串,当设备节点和驱动的

compatible相同时就匹配成功;

(2)compatible后面可以有多个字符串,优先匹配靠前的字符串,靠前的字符串匹配不上才会匹配后面的字符串;

5.3、model属性格式

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

	memory {
		device_type = "memory";
		reg = ;
	};};

(1)model是描述模块信息的,一般只有根节点才有,标明设备树文件对应的开发板的名称;

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

5.4、status属性格式

&uart0 {
	status = "okay";
};
状态值 含义
okey 表示设备是可操作的
disabled 表示当前不可操作,但是后续是可以更改为可操作性的
fail、failed 表示有严重错误,几乎不可能再可操作了

(1)status描述设备信息状态,在设备树文件中可以根据需求设置模块的状态,功能就是开启/关闭某个模块;

(2)在dtsi文件中,默认都是关闭模块的,在开发板对应的dts文件中自己去打开需要的模块;

5.5、reg属性格式

clock: clock@12010000 {
	compatible = "hisilicon,hi3516dv300-clock";
	#address-cells = <1>;	/* 表示reg里面的数据address占用一个字长*/
	#size-cells = <1>;		/* 表示reg里面的数据size占用一个字长,注意字长不是字节*/
	#clock-cells = <1>;
	#reset-cells = <2>;
	reg = <0x12010000 0x1000>;	/*起始地址是0x12010000,长度是0x1000*/
};
  • reg属性:配置某个硬件模块对应的地址范围信息;

  • #address-cells属性:表示reg里面的数据address占用的字长,注意字长不是字节;

  • #size-cells:表示reg里面的数据size占用的字长,注意字长不是字节;

  • reg = :address一般用来表示起始地址,length一般表示持续长度;

5.6、中断属性格式

gic: interrupt-controller@10300000 {
	compatible = "arm,cortex-a7-gic";
	#interrupt-cells = <3>;	/*表示interrupts用三个cell来描述中断*/
	#address-cells = <0>;
	interrupt-controller;	/*标明gic节点是中断控制器*/
	/* gic dist base, gic cpu base , no virtual support */
	reg = <0x10301000 0x1000>, <0x10302000 0x100>;
 };
	
ipcm: ipcm@045E0000 {
	compatible = "hisilicon,ipcm-interrupt";
	interrupt-parent = <&gic>;	/*父节点是gic节点*/
	interrupts = <0 10 4>;	/*<中断域 中断 触发方式>*/
	reg = <0x10300000 0x4000>;	
	status = "okay";
};

(1)interrupt-controller:无值属性,表示这是个中断控制器node
(2)#interrupt-cells:这是中断控制器节点的属性,用来标识这个控制器需要几个cell做中断描述符
(3)interrupt-parent:标识此设备节点属于哪一个中断控制器,如果没有这个属性,会自动依附父节点
(4)interrupts :一个中断标识符列表,表示每一个中断输出信号

6、特殊节点

6.1、chosen子节点

6.1.1、chosen子节点功能介绍

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

(1)chosen子节点不对应真实的设备,是用来描述内核启动参数的,对应于uboot启动内核时传递的bootargs参数;
(2)上面是摘抄的内核dts文件中的chosen子节点,里面只设置了stdout-path属性,也就是把输出设置成串口0,波特率是115200;
(3)dts文件中设置的属性会被覆盖点,具体就是uboot在启动内核时,会将bootargs启动参数转换成chosen子节点的属性,替换掉dts文件中设置的属性;

6.1.2、chosen子节点在内核中的体现

~ # 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子节点

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

aliases就是别名的意思,aliases节点主要功能就是给节点定义别名,为了方便访问节点。不过我们在节点命名的时候可以加上label标签,直接通过&label引用标签来访问也很方便,aliases节点内部其实也是通过引用标签名来定义别名;

7、节点相关操作

7.1、节点引用和内容替换

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节点*/
&gpio_chip1 {
	status = "okay";	/*替换status属性内容*/
};

对于已经定义好的节点,我们通过引用节点的方式,重新定义某些属性,效果上看就是替换掉某些属性的值;

7.2、合并节点内容

/{
	node{
		key1=value1;
	}
}

/{
	node{
		key2=value2;
	}
}

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

有时候我们需要增加硬件描述的信息,这时候就可以在后面创新定义该节点,最后解析的时候会把同名节点不同的部分进行合并;

相关推荐:《Linux视频教程

以上がLinux dtsの用途は何ですかの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。