1.设备树文件在linux中的位置:
imx-linux4.9.88\arch\arm\boot\dts(更新设备树dtb,/boot/可直接替换)
系统启动以后可以在根文件系统里面看到设备树的节点信息。在/proc/device-tree/目录下存放着设备树信息。
2.dts与dtb的区别:
.dts相当于.c,就是DTS源码文件。
.dtb相当于bin文件,或可执行文件。
3.设备树源码中常用的几种数据形式如下所示:
①、字符串
compatible = "arm,cortex-a7";
上述代码设置 compatible 属性的值为字符串“arm,cortex-a7”。
②、 32 位无符号整数
reg = <0>;
上述代码设置 reg 属性的值为 0, reg 的值也可以设置为一组值,比如:
reg = <0 0x123456 100>;
③、字符串列表
属性值也可以为字符串列表,字符串和字符串之间采用“,”隔开,如下所示:
compatible = "fsl,imx6ull-gpmi-nand", "fsl, imx6ul-gpmi-nand";
static const struct of_device_id 12345_dt_ids[] = {
{ .compatible = "fsl(厂商),led(模块对应的驱动名字)"(设备树文件中.compatible的内容), },
};
static struct platform_driver imx_xxx_driver = {
.probe = xxx_probe函数,
.remove =xxx_remove函数,
.driver = {
.name = "与硬件平台设备名字相对应",
.of_match_table = 12345_dt_ids(数组名),
},
};
4.标准属性
1)compatible 属性
compatible 属性也叫做“兼容性”属性。compatible 属性的值是一个字符串列表, compatible 属性用于将设备和驱动绑定起来。
字符串列表用于选择设备所要使用的驱动程序, compatible 属性的值格式如下所示:
"manufacturer,model"
其中 manufacturer 表示厂商, model 一般是模块对应的驱动名字。
compatible = "manufacturer,model1","manufacturer,model2";
这个设备首先使用第一个兼容值在 Linux 内核里面查找,看看能不能找到与之匹配的驱动文件,
如果没有找到的话就使用第二个兼容值查。
一般驱动程序文件都会有一个 OF 匹配表,此 OF 匹配表保存着一些 compatible 值,如果设
备节点的 compatible 属性值和 OF 匹配表中的任何一个值相等,那么就表示设备可以使用这个
驱动。
根节点/下面的compatible。内核启动的时候会检查是否支持此平台或机器:
arch/arm/mach-imx/mach-imx6ul.c与imx6ull-alientekemmc.dts 中根节点的 compatible 属性值
是否相同。
2) model 属性
model 属性值也是一个字符串,一般 model 属性描述设备模块信息,比如名字什么的,比
如:model = "wm8960-audio";
3) status 属性
status 属性看名字就知道是和设备状态有关的, status 属性值也是字符串,字符串是设备的
状态信息,可选的状态如表 43.3.3.1 所示:
值 | 描述 |
“okay” | 表明设备是可操作的。 |
“disabled” | 表明设备当前是不可操作的,但是在未来可以变为可操作的,比如热插拔设备 插入以后。至于 disabled 的具体含义还要看设备的绑定文档。 |
“fail” | 表明设备不可操作,设备检测到了一系列的错误,而且设备也不大可能变得可 操作。 |
“fail-sss” | 含义和“fail”相同,后面的 sss 部分是检测到的错误内容。 |
4、 #address-cells 和#size-cells 属性
这两个属性的值都是无符号 32 位整形, #address-cells 和#size-cells 这两个属性可以用在任
何拥有子节点的设备中,用于描述子节点的地址信息。
#address-cells 属性值决定了子节点 reg 属性中地址信息所占用的字长(32 位),
#size-cells 属性值决定了子节点 reg 属性中长度信息所占的字长(32 位)。
#address-cells 和#size-cells 表明了子节点应该如何编写 reg 属性值,一般 reg 属性都是和地址有关的内容,和地址相关的信息有两种:起始地址和地址长度。
5) reg 属性
reg 属性的值一般是(address, length)。 reg 属性一般用于描述设备地址空间资源信息,一般都是某个外设的寄存器地址范围信息。
6) ranges 属性
ranges属性值可以为空或者按照(child-bus-address,parent-bus-address,length)格式编写的数字
矩阵, ranges 是一个地址映射/转换表, ranges 属性每个项目由子地址、父地址和地址空间长度
这三部分组成:
child-bus-address:子总线地址空间的物理地址,由父节点的#address-cells 确定此物理地址
所占用的字长。
parent-bus-address: 父总线地址空间的物理地址,同样由父节点的#address-cells 确定此物
理地址所占用的字长。
length: 子地址空间的长度,由父节点的#size-cells 确定此地址长度所占用的字长。
7) name 属性
name 属性值为字符串, name 属性用于记录节点名字。
8)device_type 属性
device_type 属性值为字符串。此属性只能用于 cpu 节点或者 memory 节点。
5.在/根节点外有一些&cpu0这样的语句是“追加“。
6.intc: interrupt-controller@00a01000
intc是标签label;interrupt-controller@00a01000是名字。
7.Linux 内核源码中有详细的.txt 文档描述了如何添加节点,
Linux 源码目录/Documentation/devicetree/bindings。
8.驱动如何获取到设备树中节点信息。在驱动中使用OF函数获取设备树属性内容。
驱动要想获取到设备树节点内容,首先要找到节点。
9. 获取设备树内容:
backlight {
compatible = "pwm-backlight";
pwms = <&pwm1 0 5000000>;
brightness-levels = <0 4 8 16 32 64 128 255>;
default-brightness-level = <6>;
status = "okay";
};
/*1、找到backlight节点,路径是:/backlight */
bl_nd = of_find_node_by_path("/backlight");
if (bl_nd == NULL) { /* 失败 */
ret = -EINVAL;
goto fail_findnd;
}
/* 2、获取属性 */
comppro = of_find_property(bl_nd, "compatible", NULL);
if (comppro == NULL) { /* 失败 */
ret = -EINVAL;
goto fail_finpro;
} else { /* 成功 */
printk("compatible=%s\r\n", (char*)comppro->value);
}
ret = of_property_read_string(bl_nd, "status", &str);
if(ret < 0) {
goto fail_rs;
} else {
printk("status=%s\r\n", str);
}
/*3、 获取数字属性值 */
ret = of_property_read_u32(bl_nd, "default-brightness-level", &def_value);
if(ret < 0) {
goto fail_read32;
} else {
printk("default-brightness-level=%d\r\n", def_value);
};
/* 4、获取数组类型的属性 */
elemsize = of_property_count_elems_of_size(bl_nd, "brightness-levels", sizeof(u32));
if(elemsize < 0) {
ret = -EINVAL;
goto fail_readele;
} else {
printk("brightness-levels elems size = %d\r\n", elemsize);
};
/* 获取数组 */
ret = of_property_read_u32_array(bl_nd, "brightness-levels", brival, elemsize);
if(ret < 0) {
goto fail_read32array;
} else {
for(i = 0; i < elemsize; i++) {
printk("brightness-levels[%d] = %d\r\n", i, *(brival + i));
}
}
10. Device Tree 是一种描述硬件的数据结构,它起源于 OpenFirmware(OF)。在 Linux2.6 中,ARM 架构的板机硬件细节过多地被硬编码在 arch/arm/plat-xxx 和 arch/arm/mach-xxx,采用 Device Tree 后,许多硬件的细节可以直接透过它传递给 Linux,而不再需要在 kernel 中进行大量的冗余编码。
Device Tree 由一系列被命名的结点(node)和属性(property)组成,而结点本身可包含子节点。所谓属性,其实就是成对出现的 name 和 value 。
在 Device Tree 中,可描述的信息包括(原先这些信息大多被硬编码到 kernel 中):
- CPU的数量和类别
- 内存基地址和大小
- 总线和桥
- 外设连接
- 中断控制器和中断使用情况
- GPIO控制器和GPIO使用情况
- Clock控制器和Clock使用情况
它基本上就是画一棵电路板上(CPU、总线、设备组成)的树,Bootloader 会将这棵树传递给内核,然后内核可以识别这棵树,并根据它展开出 Linux 内核中的 platform_device、i2c_client、spi_device等设备,而这些设备用到的内存、IRQ 等资源,也被传递给了内核,内核会将这些资源绑定给展开的相应的设备。
.dts 文件是一种 ASCII 文本格式的 Device Tree 描述。基本上,在 ARM Linux 中,一个 .dts 文件对应一个 ARM 的 machine,一般放置在内核的 arch/arm/boot/dts/ 目录。由于一个 SOC 可能对应多个 machine(一个SOC可以对应多个产品和电路板),势必这些 .dts 文件需包含许多共同的部分,Linux 内核为了简化,把 SOC 公用的部分或者多个 machine 共同的部分一般提炼为 .dtsi,类似于C语言的头文件。其他的 machine 对应的 .dts 就是 include 这个 .dtsi 。