Linux设备树的规范 - DTS

【版权申明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权) 

Linux设备树的规范 - DTS

1. 语法总览

  注释: 结点 = 节点

Devicetree node格式:(设备树节点格式)

[label:] node-name[@unit-address] {
    [properties definitions]
    [child nodes]
};

解释:

字段 解释
[label:] 可以写, 也可以不写, 写的话可以方便别人引用你这个节点.
node-name 节点的名字
[@unit-address] 节点名后面可以加上一个地址(组合起来就是这个节点的名字, 如 led@0x120D6100), 用于防止节点的重名.(不同级别下的重名, 不属于重名. 即任意两个节点的全路径不能相同)
[properties definitions] 该节点属性的定义(如compatible属性: compatible = “ybk_led”; 如reg属性: reg = <0x120D6100 1>;)
[child nodes] 设备树的结点, 用于描述这个板子的硬件资源.
{ }; 代表一个节点的始末, 跟在[label:] node-name[@unit-address]之后. (如果是 / { }, 那么它是一个根节点, 是和我们Linux中的根目录同等地位的)

举个例子:

/ {
	model = "Hisilicon HI3516CV500 DEMO Board";
	compatible = "hisilicon,hi3516cv500";

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

	led@0x120D6100 {
		compatible = "ybk_led";
		reg = <0x120D6100 1>;
	};
};

2. 语法细说

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

aliases {
	serial0 = &uart0;
	serial1 = &uart1;
	serial2 = &uart2;
};

/* 修改引用节点的个别属性 */
&uart0 {
	status = "okay";
};

讲解: (label为uart0)

  由上可见, 第一个节点为uart的定义, 它的label为uart0, 在aliases节点中, 使用&uart0引用uart节点. 故label的作用是方便其它节点来引用它.
如果不使用label, 引用该节点的方式是怎么样的呢? 如下:

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

aliases {
	serial0 = <1>;
	serial1 = &uart1;
	serial2 = &uart2;
};

  由上可见, 我们使用了节点中的phandle属性来标明自己, 其它节点引用时只需要<1>就可以了, 但是缺陷也很明显, 不直观, 可读性差.
使用phandle属性时需要注意, 它的取值必须是唯一的(不要跟其他的phandle值一样).

2.1 [properties definitions]

Property的格式:

  1. property-name = value; /* 有值 */
  2. property-name; /* 没有值 */

Property的值:

  1. arrays of cells(1个或多个32位数据, 64位数据使用2个32位数据表示) (cell就是一个32位的数据)
  2. string(字符串)
  3. bytestring(1个或多个字节)

举个例子:

/* 1. arrays of cells */
interrupts = <17 0xc>;	// 0xc可能表示中断的出发类型
clock-frequency = <0x00000001 0x00000000>;	//64bit数据使用2个cell来表示:(使用两个32位数来表示)

/* 2. string(字符串), A null-terminated string (有结束符的字符串) */
compatible = "ybk_led";	//长度为8, 包含一个'0'

/* 3. bytestring(字节序列), 0不能被忽略! */
local-mac-address = [00 00 12 34 56 78];  // 每个byte使用2个16进制数来表示
local-mac-address = [000012345678];       // 每个byte使用2个16进制数来表示

/* 可以是各种值的组合, 用逗号隔开: */
compatible = "ns16550", "ns8250";
example = <0xf00f0000 19>, "a strange property format";

3. DTS的文件布局(layout)

/dts-v1/;	/* 表示dts文件的版本 */

/**
 * 表示保留的内存区域
 * (假设你的DDR有64M, 但是你不想完全给内核使用, 那么你可以使用这个选项将它保留下来供自己使用)
 * 格式为: /memreserve/ <address> <length>;
 */
[memory reservations]

/* '/'表示根, 这个是设备树的起点 */
/ {
    [property definitions]	/* 属性定义, 用于描述这个设备树属于哪一块板子. */ 
		eg:
			model = "Hisilicon HI3516CV500 DEMO Board";
			compatible = "hisilicon,hi3516cv500";
    [child nodes]	/* 设备树的结点, 用于描述这个板子的硬件资源. */
};

4. DTS特殊的、默认的属性

4.1 根节点(根节点必须有的属性):
字段 解释
#address-cells 在它的子节点的reg属性中, 使用多少个u32整数来描述地址(address)
#size-cells 在它的子节点的reg属性中, 使用多少个u32整数来描述大小(size)
compatible 定义一系列的字符串, 用来指定内核中哪个machine_desc可以支持本设备, 即这个板子兼容哪些平台. ( 每一种单板在内核里面都有一个machine_desc结构体, 里面有不同的初始化函数, 你需要指定这里的compatible属性, 来指导内核选择正确的machine_desc结构体. 也就是说这里的作用是使内核执行正确的初始化函数 )
model 这个板子是什么, 比如有2款板子配置基本一致, 它们的compatible是一样的, 那么就通过model来分辨这2款板子

对设备树中的#address-cells和#size-cells举个例子:

扫描二维码关注公众号,回复: 11135395 查看本文章
/ {
	#address-cells = <0x1>;	/* 使用1个u32来代表address */
    #size-cells = <0x0>; 	/* 使用0个u32来代表size */
    
    memory {
		device_type = "memory";
		reg = <0x82000000>;	/* 0x82000000是存取memory的address */
	};
}
/ {
	#address-cells = <0x1>;	/* 使用1个u32来代表address */
    #size-cells = <0x1>; 	/* 使用0个u32来代表size */
    
    memory {
		device_type = "memory";
		
		/**
		 * 0x82000000是存memory的address
		 * 0x20000000是存memory的size
		 */
		reg = <0x82000000 0x20000000>;	
	};
}
4.2 /memory:
字段 解释
device_type 必须等于: “memory”
reg 用来指定内存的地址、大小

举个例子:

    memory {
		device_type = "memory";
		reg = <0x82000000 0x20000000>;	
	};
4.3 /chosen:

  chosen节点不描述一个真实设备, 而是用于firmware传递一些数据给OS, 比如bootloader传递内核启动参数给内核. 示例代码如下:

chosen {
	bootargs = "noinitrd root=/dev/mtdblock4 rw init=/linuxrc";
	console="ttySAC0, 115200";
};
4.4 /cpus:

  /cpus节点下有1个或多个cpu子节点, cpu子节点中用reg属性用来标明自己是哪一个cpu. 所以 /cpus 中有以下2个属性:

字段 解释
#address-cells 在它的子节点的reg属性中, 使用多少个u32整数来描述地址(address)
#size-cells 在它的子节点的reg属性中, 使用多少个u32整数来描述大小(size), 必须设置为0
4.4 /cpus/cpu*:
字段 解释
device_type “cpu”
reg 表明自己是哪一个cpu

  官方文档: https://www.devicetree.org/specifications/

发布了68 篇原创文章 · 获赞 22 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/MACMACip/article/details/105481200
DTS