随着linux的发展,代码越来越庞大,但创始人linus 觉得提交的代码很大一份是描述各种设备的,这部分代码对内核本身来讲意义并不大,为了将linux内核中大量的设备描述相关代码进行精简,从3.0版本起引入了设备树。
dts设备树通过节点和其中的属性来描述设备,节点间可以进行嵌套,整个板子的所有设备包含在根节点中,根节点中的各子节点分别描述各个具体设备。
根节点格式:
/ {
property=value;
property=<value>;
…
};
其中property表示属性名称,value表示属性值,属性值可以是字符串,例如:
compatible = "phytium,ft-1500a";
也可以是用“<>”表示的具体数值,例如:
#address-cells = < 0x02 >;
子节点格式:
name{
property=value;
property=<value>;
…
};
或者带设备基地址的方式:
name@address{
property=value;
property=<value>;
…
};
其中name表示设备节点名称,address表示设备基地址,例如:
lpc@20000000 {
#address-cells = < 0x01 >;
#size-cells = < 0x00 >;
compatible = "phytium,lpc\0simple-bus";
reg = < 0x00 0x20000000 0x00 0x100 >;
interrupts = < 0x00 0x21 0x04 >;
status = "disabled";
phytium,lpc-gpio;
};
test.dts设备树文件例子:
/*版本说明,没有版本说明编译成dtb的时候报错*/
/dts-v1/;
/*根节点*/
/ {
/*属性*/
compatible = "phytium,ft-1500a";
interrupt-parent = < 0x01 >;
#address-cells = < 0x02 >;
#size-cells = < 0x02 >;
model = "Phytium ft1500a generic board";
/*子节点*/
memory {
device_type = "memory";
reg = < 0x00 0x80000000 0x00 0x80000000 >;
};
/*子节点*/
interrupt-controller@29800000 {
compatible = "arm,gic-v3";
#interrupt-cells = < 0x03 >;
#address-cells = < 0x02 >;
#size-cells = < 0x02 >;
ranges;
interrupt-controller;
reg = < 0x00 0x29800000 0x00 0x10000 0x00 0x29a00000 0x00 0x200000 0x00 0x29c00000 0x00 0x10000 0x00 0x29c10000 0x00 0x10000 0x00 0x29c20000 0x00 0x10000 >;
interrupts = < 0x01 0x09 0x04 >;
linux,phandle = < 0x01 >;
phandle = < 0x01 >;
};
/*子节点*/
soc {
/*属性*/
compatible = "simple-bus";
#address-cells = < 0x02 >;
#size-cells = < 0x02 >;
dma-coherent;
ranges;
/*嵌套子节点*/
lpc@20000000 {
#address-cells = < 0x01 >;
#size-cells = < 0x00 >;
compatible = "phytium,lpc\0simple-bus";
reg = < 0x00 0x20000000 0x00 0x100 >;
interrupts = < 0x00 0x21 0x04 >;
status = "disabled";
phytium,lpc-gpio;
};
};
};
将dts文件编译成二进制dtb格式文件:
dtc -I dts -O dtb test.dts -o test.dtb
查看编译后的dtb格式文件:
hexdump -C test.dtb
dtb文件存储格式是大端模式(big endin 低地址存高字节,高地址存低字节),第一个红框中的数据是文件头,文件头定义如下:
struct fdt_header {
fdt32_t magic; /* magic word FDT_MAGIC */
fdt32_t totalsize; /* total size of DT block */
fdt32_t off_dt_struct; /* offset to structure */
fdt32_t off_dt_strings; /* offset to strings */
fdt32_t off_mem_rsvmap; /* offset to memory reserve map */
fdt32_t version; /* format version */
fdt32_t last_comp_version; /* last compatible version */
/* version 2 fields below */
fdt32_t boot_cpuid_phys; /* Which physical CPU id we're
booting on */
/* version 3 fields below */
fdt32_t size_dt_strings; /* size of the strings block */
/* version 17 fields below */
fdt32_t size_dt_struct; /* size of the structure block */
};
magic:0xd00dfeed //魔数
totalsize:0x000003e8 //dtb文件总长度
off_dt_struct:0x00000038 //设备树结构起始地址在dtb中的偏移位置
设备树结构包含两部分
节点头:
struct fdt_node_header {
/*节点标识,节点起始:0x00000001,节点结束:0x00000002
一组0x00000001和0x00000002表示一个完整节点
*/
fdt32_t tag;
/*节点名称,根节点无名称为:0x00000000*/
char name[0];
};
节点属性:
struct fdt_property {
/*属性标识,0x00000003*/
fdt32_t tag;
/*属性长度*/
fdt32_t len;
/*属性名称相对字符串起始位置的偏移*/
fdt32_t nameoff;
/*属性值*/
char data[0];
};
上图中第一节点(根节点)属性如下:
属性标识:0x00000003
属性长度:0x11,属性长度为17
属性名称在属性字符串块中的偏移,属性字符串块如下:
偏移0x00000000,表示第一个属性字符串:compatible
属性值:70 68 79 74 69 75 6d 2c 66 74 2d 31 35 30 30 61
对应字符串:phytium,ft-1500a
off_dt_strings:0x00000330 属性名称字符串起始地址在dtb中的偏移位置
off_mem_rsvmap:0x00000028 保留内存地址
version:0x11 版本号为17
last_comp_version: 0x10 上一个兼容版本号为16
boot_cpuid_phys: 0x0 使用的CPUid号
size_dt_strings:0xb8 属性字符串块长度 (上图最后一个红框内容)
size_dt_struct:0x2f8 结构块长度(上图2个红框之间的内容)