设备树DTS简介及DTS基本语法
参考资料:
在linux3.1版本引入设备树
设备树用来描述板级信息
编译设备树:
make all // 全编译,包括内核镜像和dtb make dtbs // 编译所有的设备树文件 make imx6ull-14x14-emmc-4.3-800x480-c.dtb // 编译单个dtb
dtc反编译出dts方法:
sudo apt install device-tree-compiler
通过安装device-tree-compiler工具,可以通过下面的命令进行将dtb反编译出dts:
fdtdump imx6ull-14x14-emmc-4.3-800x480-c.dtb > test.txt 或 dtc -I dtb -O dts -o test.dts imx6ull-14x14-emmc-4.3-800x480-c.dtb
DTS语法基本语法:
1、.dtsi头文件
和c语言一样,也有头文件的概念,举个例子:
为了适应不同的屏幕,其他的设备树内容都是一样的,那么就可以不同屏幕的设备创建不同分辨率的设备树dts文件
设备树不仅可以引用.dtsi头文件,也可以直接引用c语言的.h头文件,用来说明一些dts规范
2、设备节点
如下截取设备树部分:
{ // 根节点,多个文件的根节点在dtc时会汇总为一个 aliases { can0 = &flexcan1; }; cpus { #address-cells = <1>; #size-cells = <0>; cpu0: cpu@0 { compatible = "arm,cortex-a7"; device_type = "cpu"; reg = <0>; }; }; intc: interrupt-controller@00a01000 { compatible = "arm,cortex-a7-gic"; #interrupt-cells = <3>; interrupt-controller; reg = <0x00a01000 0x1000>, <0x00a02000 0x100>; }; }
节点命令格式:
label: node-name@unit-address
label是个标签,label 的目的就是为了方便访问节点,可以直接通过&label 来访问这个节点,比如通过&cpu0 就可以访问“cpu@0”这个节点,而不需要输入完整的节点名字
node-name是节点名字,为 ASCII 字符串
unit-address是节点基地址
基本节点属性:
compatible = "arm,cortex-a7"; // 字符串属性,compatible 属性的值为字符串“arm,cortex-a7 reg = <0>; // 32位无符号整数,reg属性的值为0 compatible = "fsl,imx6ull-gpmi-nand", "fsl, imx6ul-gpmi-nand"; // 属性值也可以为字符串列表,字符串和字符串之间采用“,”隔开,代码设置属性 compatible 的值为“fsl,imx6ull-gpmi-nand”
和“fsl, imx6ul-gpmi-nand”。
3、标准属性
3.1 compatible属性
这个是跟驱动进行匹配的
一般驱动程序文件都会有一个 OF 匹配表,此 OF 匹配表保存着一些 compatible 值,如果设备节点的 compatible 属性值和 OF 匹配表中的任何一个值相等,那么就表示设备可以使用这个驱动
3.2 status属性
status 属性看名字就知道是和设备状态有关的,status 属性值也是字符串
可选状态有:
okay // 表示设备可以操作 disabled // 表示设备当前不可操作 fail // 表示设备不可操作,没用过 fail-sss // 表示设备不可操作,也没用过
3.3 #address-cells 、#size-cells 属性和reg属性
这两个属性的值都是无符号 32 位整形,#address-cells 和#size-cells 这两个属性可以用在任何拥有子节点的设备中,用于描述子节点的地址信息。#address-cells 属性值决定了子节点 reg 属性中地址信息所占用的字长(32 位),#size-cells 属性值决定了子节点 reg 属性中长度信息所占的字长(32 位)。#address-cells 和#size-cells 表明了子节点应该如何编写 reg 属性值,一般 reg 属性都是和地址有关的内容,和地址相关的信息有两种:起始地址和地址长度,reg 属性的格式一为:
reg = <address1 length1 address2 length2 address3 length3……>
例如下面节点:
aips3: aips-bus@02200000 { compatible = "fsl,aips-bus", "simple-bus"; #address-cells = <1>; #size-cells = <1>; dcp: dcp@02280000 { compatible = "fsl,imx6sl-dcp"; reg = <0x02280000 0x4000>; }; };
子节点 dcp: dcp@02280000 的 reg 属性值为<0x02280000 0x4000>,因为父节点设置了#address-cells = <1>,#size-cells = <1>,address= 0x02280000,length= 0x4000,相当于设置了起始地址为 0x02280000,地址长度为 0x40000。
3.4 追加设备节点
例如向i2c1追加mag3110设备,则可如下设置:
&i2c1 { clock-frequency = <100000>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_i2c1>; status = "okay"; mag3110@0e { compatible = "fsl,mag3110"; reg = <0x0e>; position = <2>; }; };
这个就是向i2c1节点追加mag3110设备,重点就是通过&i2c1来访问节点,然后直接在里面编写要追加或者修改的内容。
3.5 alias子节点
aliases { can0 = &flexcan1; can1 = &flexcan2; ethernet0 = &fec1; ethernet1 = &fec2; gpio0 = &gpio1; gpio1 = &gpio2; gpio2 = &gpio3; gpio3 = &gpio4; gpio4 = &gpio5; ... spi0 = &ecspi1; spi1 = &ecspi2; spi2 = &ecspi3; spi3 = &ecspi4; };
aliases 节点的主要功能就是定义别名,定义别名的目的就是为了方便访问节点。不过我们一般会在节点命名的时候会加上 label,然后通过&label来访问节点,这样也很方便,而且设备树里面大量的使用&label 的形式来访问节点。
3.6 chosen 子节点
chosen 并不是一个真实的设备,chosen 节点主要是为了 uboot 向 Linux 内核传递数据,重点是 bootargs 参数。
例如当前我的开发板的chosen节点下bootargs如下:
如何来的可见:
以上就是最基本的设备树基础语法