>  기사  >  운영 및 유지보수  >  리눅스 dts의 용도는 무엇입니까

리눅스 dts의 용도는 무엇입니까

青灯夜游
青灯夜游원래의
2023-03-14 10:34:081464검색

Linux에서 dts는 장치 정보를 설명하는 데 사용되는 장치 트리 소스 파일입니다. 장치 트리 기술은 장치의 하드웨어 리소스 정보를 dts 파일에 기록합니다. 장치 트리 소스 파일 dts는 dtb 바이너리로 컴파일되어 부트로더가 실행 중일 때 운영 체제로 전달됩니다. 운영 체제는 이를 구문 분석하고 확장하여 이 토폴로지 다이어그램을 사용하여 컴파일 프로세스를 수행할 수 있습니다. 시스템에서 제공하는 인터페이스를 통해 직접 전달되며 장치 트리의 노드 및 속성 정보를 얻습니다.

리눅스 dts의 용도는 무엇입니까

이 튜토리얼의 운영 환경: linux7.3 시스템, Dell G3 컴퓨터.

1. 디바이스 트리란 무엇인가요?

장치 트리(dt: 장치 트리)는 Linux 커널에서 사용하는 매개변수 표현 및 전송 기술로, 시스템 부팅 단계에서 장치를 초기화할 때 장치 트리에 설명된 하드웨어 정보가 운영 체제로 전송됩니다.

  • dts(장치 트리 소스): 장치 정보를 설명하는 장치 트리 소스 파일

    장치 트리 소스 파일 dts는 dtb 바이너리로 컴파일되어 부트로더가 실행 중일 때 운영 체제로 전달되며, 시스템은 이를 구문 분석하고 확장하여 하드웨어 장치의 토폴로지 다이어그램을 생성합니다. 이 토폴로지 다이어그램을 사용하면 컴파일 프로세스 중에 시스템이 제공하는 인터페이스를 통해 장치 트리의 노드 및 속성 정보를 직접 얻을 수 있습니다. dtc(장치 트리 컴파일러): 장치 트리 컴파일/디컴파일/디버깅 도구


  • dtb(장치 트리 바이너리): 바이너리 장치 트리 이미지
  • dtsi(장치 트리 소스 포함): 다음과 같은 기능을 하는 헤더 파일 장치 트리 파일이며 include, dtsi를 통해 dts 파일에서 참조할 수 있습니다. 이 파일은 일반적으로
  • 2 장치 드라이버에서 어떤 문제를 해결합니까? 소스 코드는 드라이버 코드와 장치 코드로 구분됩니다. 드라이버 코드는 하드웨어를 작동하는 방법이고, 장치 코드는 하드웨어 리소스와 데이터입니다. 드라이버 코드와 장치 코드가 일치하면 드라이버의 프로브 기능이 수행됩니다. 프로브 기능은 장치 코드의 리소스를 사용하여 장치를 초기화합니다.

장치 트리 이전에는 장치 코드가 커널에 직접 작성됩니다. 소스 코드에서는 platform_device 구조의 형태로 존재합니다. 드라이버 코드와 장치 코드는 플랫폼 버스에서도 일치합니다. 장치 리소스를 수정해야 할 경우 커널 소스 코드를 수정해야 합니다.

디바이스 트리 기술은 장치의 하드웨어 리소스 정보를 변환합니다. 수정해야 할 경우 커널 소스 코드를 수정하지 않고 dts 파일을 수정하세요.
  • 장치 트리 기술을 사용하지 않습니다. 커널 소스 코드는 많은 양의 장치 하드웨어로 채워집니다. 설명 정보로 인해 커널 소스 코드가 계속 증가하지만 하드웨어 설명 정보 코드는 커널 기능과 관련이 없습니다.
  • 장치 트리 기술을 사용한 후: 장치의 하드웨어 설명 정보는 dts에 있습니다. 수정하기 쉽지만 커널은 dts 파일 형식을 구문 분석하는 코드를 추가해야 합니다.
  • 3. 장치 트리는 어떻게 작동합니까? 향후 드라이버 코드가 적절한 장치 하드웨어 정보와 일치할 수 있도록 하드웨어에 따라 dts 파일을 수정합니다.
  • 커널을 컴파일할 때 커널은 먼저 dtc를 컴파일한 다음 dtc를 사용하여 dts 파일을 dtb로 컴파일합니다.
  • uboot는 커널을 시작할 때 커널 이미지와 dtb를 메모리에 재배치하고 커널에 dtb의 메모리 주소를 알려줍니다.

커널 시작 초기 단계에서 구문 분석을 위해 내부 함수가 호출됩니다. dtb, 하드웨어 정보를 얻은 후 하드웨어 기능으로 조립되고 최종적으로 드라이버 코드와 일치합니다.

리눅스 dts의 용도는 무엇입니까4. 장치 트리 소스 코드 dts 파일 형식에 대한 설명

  • 4.1 커널 소스 코드의 dts 파일 저장 위치

  • arm 아키텍처: arch/arm/boot/dts 디렉토리

4.2 dts 파일 형식 소개

댓글의 경우 +

/dts-v1/node는 dts의 버전 번호를 나타내며 현재 v1/{}은 루트 노드입니다. 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视频教程

위 내용은 리눅스 dts의 용도는 무엇입니까의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.