DT:Device Tree //设备树
FDT: Flattened Device Tree //开放设备树,起源于OpenFirmware (所以后续会见到很多OF开头函数)
dts: device tree source的缩写 //设备树源码
dtsi: device tree source include的缩写 //通用的设备树源码<5>dtb: device tree blob的缩写//编译设备树源码得到的文件
dtc: device tree compiler的缩写 //设备树编译器
dis和dtsi文件通过dtc编译器,生成dtb设备树二进制文件。
DTC编译器在内核源码:
alientek@ubuntu16:~/linux/linux-imx-4.1.15-2.1.0-g3dc0a4b-v2.7$ find -name dtc.c./drivers/scsi/dtc.c
./scripts/dtc/dtc.c
alientek@ubuntu16:~/linux/linux-imx-4.1.15-2.1.0-g3dc0a4b-v2.7$ cd ./scripts/dtc/dtc.c
bash: cd: ./scripts/dtc/dtc.c: Not a directory
alientek@ubuntu16:~/linux/linux-imx-4.1.15-2.1.0-g3dc0a4b-v2.7$ cd ./scripts/dtcalientek@ubuntu16:~/linux/linux-imx-4.1.15-2.1.0-g3dc0a4b-v2.7/scripts/dtc$ ls
checks.c dtc-parser.tab.h Makefile
checks.o dtc-parser.tab.h_shipped Makefile.dtc
data.c dtc-parser.tab.o modules.order
data.o dtc-parser.y srcpos.c
dtc fdtdump.c srcpos.h
dtc.c fdtget.c srcpos.o
dtc.h fdtput.c treesource.c
dtc-lexer.l flattree.c treesource.o
dtc-lexer.lex.c flattree.o update-dtc-source.sh
dtc-lexer.lex.c_shipped fstree.c util.c
dtc-lexer.lex.o fstree.o util.h
dtc.o libfdt util.o
dtc-parser.tab.c livetree.c version_gen.h
dtc-parser.tab.c_shipped livetree.o
编译内核时候,会同步编译dtc。
指令格式 dtc [-I input-format] [-O output-format][-o output-filename] [-V output_version] input_filename
编译设备树:dtc -I dts -O dtb -o xxx.dtb xxx.dts
反编译设备树:dtc -I dtb -O dts -o xxx.dts xxx.dtb
简单写一个dts
/dts-v1/;
/ {
};
编译与反编译
在Linux根目录下,用make dtbs 可以编译所有设备树。
arch/arm/boot/dts/Makefile,通过比配置,控制编译那些设备树
dtb-$(CONFIG_SOC_IMX6UL) += \
imx6ul-14x14-ddr3-arm2.dtb \
imx6ul-14x14-ddr3-arm2-emmc.dtb \
.........
imx6ul-9x9-evk-csi.dtb \
imx6ul-9x9-evk-ldo.dtb
和 C 语言一样,设备树也支持头文件,设备树的头文件扩展名为.dtsi,也可以引用 C 语言中的.h 文件,甚至也可以引用.dts 文件,例如
#include
#include "xxxxx.dtsi"
一般.dtsi 描述板级信息(也就是开发板上有哪些 IIC 设备、SPI 设备等,由芯片厂提供),.dts 描述 SOC 级信息(各个外设控制器信息、那个iic上挂哪个传感器等),这样写的好处是,将芯片平台与下游odm分开,通过dts拓展原始基础dtsi。
根节点是设备树必须要包含的节点。根节点的名字是/。
子节点格式为
[label:]node-name[@unit-address]{
[properties definitions]
[child nodes]
};
举例:
node1{//子节点,节点名称为node1
node1_child{//子子节点,节点名称为node1_child
};
};
同级节点下节点名称不能相同,不通级节点名称可以相同。
label 标签:引入 label 的目的就是为了方便访问节点,可以直接通过&label 来访问这个节点。
node-name名称:必须要有。
unit-address:设备地址,这里的设备地址没有实际用处,只是为了代码可读性的要求。
举例:
aliases(
mmc0= &sdmmc0
mmc1 = &sdmmc1:
mmc2 = &sdhci:
serial0="/simple@fe000000/serial@llc500”
}
chosen{
bootargs = "root=/dev/nfs rw nfsroot=192.168.1.1 console=ttyS0,115200"
}
如果包含gpio-controller,该节点就是gpio控制器;
如果包含interrupt-controller,该节点就是gpio控制器;
interrunt-parent=<&gpio0>;
向节点追加内容,相当于硬件上,在soc厂商的基础上,添加字节的硬件。比如,要在iic总线上挂载一个六轴设备,soc厂商可能给一个例程,也可能不给,就要自己修改和添加。
比如dtsi中:
i2c1: i2c@021a0000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl,imx6ul-i2c", "fsl,imx21-i2c";
reg = <0x021a0000 0x4000>;
interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX6UL_CLK_I2C1>;
status = "disabled";
};
可以直接在dtsi中加,但是代码复用性就降低了。在dts中追加:
&i2c1 {
clock-frequency = <100000>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c1>;
status = "okay";
mag3110@0e {
compatible = "fsl,mag3110";
reg = <0x0e>;
position = <2>;
};
ap3216c@1e {
compatible = "ap3216c";
reg = <0x1e>;
};
};
这里就追加了几个属性和两个子节点。
其中,status属性进行了改写,属性名形同时,追加的值会覆盖原有的值。
在中断控制器中,必须有一个属性#interrupt-cells,表示其他节点如果使用这个中断控制器需要几个cell来表示使用哪一个中断。
在中断控制器中,必须有一个属性interrupt-controller,表示他是中断控制器。
在设备树中使用中断,需要使用属性interrupt-parent=<&XXXX>表是中断信号链接的是哪个中断控制器。接着使用interrupts属性来表示中断引脚和触发方式。
注: interrupt里有几个cell,是由interrupt-parent对应的中断控制器里面的#interrupt-cells属性决定。
//原厂BSP工程师编写
gpio1: gpio@209c000{
compatible = "fsl,imx6ul-gpio","fsl,imx35-gpio";
reg = <0x0209c000 0x4000>;
interrupts = <GIC_SPI 66 IROTYPE LEVEL HIGH>,<GIC SPI 67 IRO TYPE LEVEL HIGH>;
gpio-controller;//该节点可以是gpio控制器
#gpio-cells = <2>;
interrupt-controller;//该节点也可以是中断控制器
#interrupt-cells = <2>;//引用该节点的节点中,interrupt-controller属性中数据的个数
}
//开发人员编写
edt-ft5x06g38{
compatible = "edt,edt-ft5x06”,"edt,edt-ft5406","edtedt-ft5306";
pinctrl-names = "default";
pinctrl-0 = <&ts_int_pin,
&ats_reset_pin>;
reg = <0X38>;
interrupt-parent = <&gpio1>;
interrupts = <9 0>;
reset-gpios = <&gpio5 9 GPIO ACTIVE_LOW>;//低电平触发
irq-gpios = <&gpio1 9 GPIO ACTIVE LOW>;
status = "disabled";
}
设备树被内核解析以后,可以在/proc/device-tree/目录中查看。
设备树机制是源于IEEE 1275 Open Firmware standard规范,相关的代码都是继承下来的,因此内核中设备树相关的函数都是以of开头的。
位置:include/linux/of.h
Linux设备树常用的OF函数总结