ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

Linux设备树学习 简记

2022-07-25 15:36:25  阅读:223  来源: 互联网

标签:cells Linux 地址 reg 简记 address 设备 节点 属性


目录

参考:https://blog.csdn.net/qq_35031421/article/details/105002645

一、结构示例

jz2440的设备树:
s3c2440-jz2440.dts
	  (include)----> s3c2440.dtsi
        	(include)----> s3c24xx.dtsi
               		 (include)----> skeleton.dtsi
        	(include)----> s3c2440-pinctrl.dtsi 

make dtbs后的设备树:
s3c2440-jz2440.dtb

设备树是一种描述硬件的数据结构。

(1) DTS: .dts文件是设备树的源文件。
(2) DTSI:一个系列的多款开发板可能包含很多共同的部分,共同的部分一般被提炼为一个或多个.dtsi 文件。
(3) DTC: DTC是将.dts编译为.dtb的工具,相当于gcc。
(4) DTB: .dtb文件是 .dts 被 DTC 编译后的二进制格式的设备树文件,它可以被linux内核解析。

二、节点

设备树中节点命名格式
node-name@unit-address
node-name: 设备节点的名称。为ASCII字符串,节点名字应该能够清晰的描述出节点的功能,比如“uart1”就表示这个节点是UART1外设;
unit-address: 一般表示设备寄存器首地址或者index。如果某个节点没有地址或者寄存器的话 “unit-address” 可以不要;

节点示例:

在上图中:多个cpu 和 ethernet依靠不同的unit-address 来分辨;可见,node-name相同的情况下,可以通过不同的unit-address定义不同的设备节点。

2.1 根节点

没有node-name 或者 unit-address,它被定义为 /。

2.2 特殊节点

/aliases 子节点

aliases 节点的主要功能就是定义别名,定义别名的目的就是为了方便访问节点。例如:定义 flexcan1 和 flexcan2 的别名是 can0 和 can1。

aliases {
	can0 = &flexcan1;
	can1 = &flexcan2;
};

/memory 子节点

所有设备树都需要一个memory设备节点,它描述了系统的物理内存布局。如果系统有多个内存块,可以创建多个memory节点,或者可以在单个memory节点的reg属性中指定这些地址范围和内存空间大小。
例如:一个64位的系统有两块内存空间:RAM1: 起始地址是0x0,地址空间是 0x80000000;RAM2: 起始地址是0x10000000,地址空间也是0x80000000;同时根节点/下的 #address-cells = <2>和#size-cells = <2>,这个memory节点描述为:

memory@0 {
	device_type = "memory";
	reg = <0x00000000 0x00000000 0x00000000 0x80000000
		   0x00000000 0x10000000 0x00000000 0x80000000>;
};

或者:

memory@0 {
	device_type = "memory";
	reg = <0x00000000 0x00000000 0x00000000 0x80000000>;
};
memory@10000000 {
	device_type = "memory";
	reg = <0x00000000 0x10000000 0x00000000 0x80000000>;
};

/chosen 子节点 (uboot的设备树中使用)

chosen 并不是一个真实的设备, chosen 节点主要是为了 uboot 向 Linux 内核传递数据,重点是 bootargs 参数。例如:

chosen {
	bootargs = "root=/dev/nfs rw nfsroot=192.168.1.1 console=ttyS0,115200";
};

/cpus 和 /cpus/cpu* 子节点

/cpus节点下有1个或多个cpu子节点,
/cpus节点的 #size-cells 必须设置为0,
/cpus/cpu* 子节点中用reg属性用来标明自己是哪一个cpu。

// RK3288:
cpus {
		#address-cells = <1>;
		#size-cells = <0>;

		cpu0: cpu@500 {
			device_type = "cpu";
			compatible = "arm,cortex-a12";
			reg = <0x500>;
			resets = <&cru SRST_CORE0>;
			operating-points = <
				/* KHz    uV */
				1608000 1350000
				1512000 1300000
			>;
			#cooling-cells = <2>; /* min followed by max */
			clock-latency = <40000>;
			clocks = <&cru ARMCLK>;
		};
		cpu1: cpu@501 {
			device_type = "cpu";
			compatible = "arm,cortex-a12";
			reg = <0x501>;
			resets = <&cru SRST_CORE1>;
		};
		cpu2: cpu@502 {
			device_type = "cpu";
			compatible = "arm,cortex-a12";
			reg = <0x502>;
			resets = <&cru SRST_CORE2>;
		};
		cpu3: cpu@503 {
			device_type = "cpu";
			compatible = "arm,cortex-a12";
			reg = <0x503>;
			resets = <&cru SRST_CORE3>;
		};
	};

2.3 节点属性

compatible

manufacturer,model
manufacturer : 表示厂商; model : 一般是模块对应的驱动名字。设备树中的设备 与 内核中的驱动(machine_desc) 利用该值进行绑定。
例如:
compatible = "fsl,mpc8641", "ns16550";
上面的compatible有两个属性,分别是 “fsl,mpc8641” 和 “ns16550”;设备首先会使用第一个属性值在 Linux 内核里面查找,看看能不能找到与之匹配的驱动文件;如果没找到,就使用第二个属性值查找。
注:一般驱动程序文件都会有一个 OF 匹配表,此 OF 匹配表保存着一些 compatible 值,如果设备节点的 compatible 属性值和 OF 匹配表中的任何一个值相等,那么就表示设备可以使用这个驱动。

model

用于标识开发板(名字),推荐的格式是“manufacturer,model-name”
model = "Samsung S3C2416 SoC";

phandle

phandle属性为devicetree中唯一的节点指定一个数字标识符,节点中的phandle属性,它的取值必须是唯一的(不要跟其他的phandle值一样),例如:

pic@10000000 {
    phandle = <1>;
    interrupt-controller;
};
another-device-node {
    interrupt-parent = <1>;   // 使用phandle值为1来引用上述节点
};

注:DTS中的大多数设备树将不包含显式的phandle属性,当DTS被编译成二进制DTB格式时,DTC工具会自动插入phandle属性。

status

字符串,描述设备的状态信息,可选的状态如下表所示:
status值 描述
“okay” 表明设备是可操作的。
“disabled” 表明设备当前是不可操作的,但是在未来可以变为可操作的,比如热插拔设备插入以后。至于 disabled 的具体含义还要看设备的绑定文档。
“fail” 表明设备不可操作,设备检测到了一系列的错误,而且设备也不大可能变得可操作。
“fail-sss” 含义和“fail”相同,后面的 sss 部分是检测到的错误内容

#address-cells#size-cells

#address-cells#size-cells 表明了子节点应该如何编写 reg 属性值:起始地址(address)和地址长度(size)。
#address-cells 决定了在它的子节点的reg属性中, 使用多少个u32整数来描述地址(address),
#size-cells 决定了在它的子节点的reg属性中, 使用多少个u32整数来描述大小(size)、(len)。

reg = <address1 size1 address2 size2 address3 size3 ……>

例如一个64位的处理器:

soc {
	#address-cells = <2>; /*子节点的reg中,addr占64位*/
	#size-cells = <1>;    /*子节点的reg中,size占32位*/
	serial {
		compatible = "xxx";
		reg = <0x4600 0x5000 0x100>;  /*地址信息是64位:0x00004600 00005000,长度信息是32位:0x00000100*/
		};
};

reg 属性

reg 属性的值一般是 (address, length) ,reg 属性一般用于描述设备地址空间资源信息,一般都是某个外设的寄存器地址范围信息。
例如:一个设备有两个寄存器块,一个的地址是0x3000,占据32字节;另一个的地址是0xFE00,占据256字节,表示如下:
reg = <0x3000 0x20 0xFE00 0x100>;
注:上述对应#address-cells = <1>;(32位) #size-cells = <1>;(32位)

ranges 属性(略)

ranges属性值可以为空或者按照 (child-bus-address,parent-bus-address,length) 格式编写的数字矩阵, ranges 是一个地址映射/转换表, ranges 属性每个项目由子地址、父地址和地址空间长度这三部分组成:
child-bus-address: 子总线地址空间的物理地址,由父节点的 #address-cells 确定此物理地址所占用的字长。
parent-bus-address: 父总线地址空间的物理地址,同样由父节点的 #address-cells 确定此物理地址所占用的字长。
length: 子地址空间的长度,由父节点的 #size-cells 确定此地址长度所占用的字长。

soc {
	compatible = "simple-bus";
	#address-cells = <1>;
	#size-cells = <1>;
	ranges = <0x0 0xe0000000 0x00100000>;
	serial {
		device_type = "serial";
		compatible = "ns16550";
		reg = <0x4600 0x100>;
		clock-frequency = <0>;
		interrupts = <0xA 0x8>;
		interrupt-parent = <&ipic>;
		};
};

soc的ranges值 <0x0 0xe0000000 0x00100000>,指定了一个 1024KB(0x00100000) 的地址范围,子地址空间的物理起始地址为 0x0,父地址空间的物理起始地址为 0xe0000000。
serial是串口设备节点, 它的reg 属性定义了 serial 设备寄存器的起始地址为 0x4600,寄存器长度为 0x100。经过ranges属性的地址转换, serial 设备可以从 0xe0004600 开始进行读写操作,0xe0004600=0x4600+0xe0000000。

name 属性(略)

name 属性值为字符串, name 属性用于记录节点名字, name 属性已经被弃用,不推荐使用name 属性,一些老的设备树文件可能会使用此属性。

device_type 属性

此属性只能用于 cpu 节点或者 memory 节点。

#include "rk3288.dtsi"
/ {
	memory@0 {
		device_type = "memory";
                      /*高32 低32 高32 低32*/
		reg = <0x0 0x0 0x0 0x80000000>;
	};

2.3 引用其他节点

phandle

pic@10000000 {
    phandle = <1>;
    interrupt-controller;
};

another-device-node {
    interrupt-parent = <1>;   // 使用phandle值为1来引用上述节点
};

label

PIC: pic@10000000 {
    interrupt-controller;
};

another-device-node {
    interrupt-parent = <&PIC>;   // 使用label来引用上述节点, 
                                 // 使用lable时实际上也是使用phandle来引用, 
                                 // 在编译dts文件为dtb文件时, 编译器dtc会在dtb中插入phandle属性
};

三、DTB格式

DTB文件主要包含四部分内容:
① struct ftd_header: 用来表明各个分部的偏移地址,整个文件的大小,版本号等;
② memory reservation block: 在设备树中使用/memreserve/ 定义的保留内存信息;
③ structure block: 保存节点的信息,节点的结构;
④ strings block: 保存属性的名字,单独作为字符串保存;
总结:
(1) DTB文件可以分为四个部分:struct ftd_header、memory reservation block、structure block、strings block;
(2) 最开始的为struct ftd_header,包含其它三个部分的偏移地址;
(3) memory reservation block记录保留内存信息;
(4) structure block保存节点的信息,节点的结构;
(5) strings block保存属性的名字,将属性名字单独作为字符串保存;

struct ftd_header结构体的定义如下:

struct fdt_header {
	uint32_t magic; /*它的值为0xd00dfeed,以大端模式保存*/
	uint32_t totalsize; /*整个DTB文件的大小*/
	uint32_t off_dt_struct; /*structure block的偏移地址*/
	uint32_t off_dt_strings; /*strings block的偏移地址*/
	uint32_t off_mem_rsvmap; /*memory reservation block的偏移地址*/
	uint32_t version; /*设备树版本信息*/
	uint32_t last_comp_version; /*向后兼容的最低设备树版本信息*/
	uint32_t boot_cpuid_phys; /*CPU ID*/
	uint32_t size_dt_strings; /*strings block的大小*/
	uint32_t size_dt_struct; /*structure block的大小*/
};

fdt_reserve_entry结构体如下:
该结构体用于表示memreserve的起始地址和内存空间的大小,它紧跟在struct ftd_header结构体后面。例如:/memreserve/ 0x33000000 0x10000,fdt_reserve_entry 结构体的成员 address = 0x33000000,size = 0x10000。

struct fdt_reserve_entry {
	uint64_t address;  /*64bit 的地址*/
	uint64_t size;    /*保留的内存空间的大小*/
};

structure block是用于描述设备树节点的结构,保存着节点的信息、节点的结构,它有5种标记类型:
① FDT_BEGIN_NODE (0x00000001):表示节点的开始,它的后面紧跟的是节点的名字;
② FDT_END_NODE (0x00000002):表示节点的结束;
③ FDT_PROP (0x00000003) :表示开始描述节点里面的一个属性,在FDT_PROP后面紧跟一个结构体如下所示:

struct {
	uint32_t len;       /*表示属性值的长度*/
	uint32_t nameoff;   /*属性的名字在string block的偏移*/
} 
注:这个结构体后紧跟着是属性值,属性的名字保存在字符串块(Strings block)中。

④ FDT_END (0x00000009):表示structure block的结束。

标签:cells,Linux,地址,reg,简记,address,设备,节点,属性
来源: https://www.cnblogs.com/solo666/p/16517228.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有