设备树简单理解就是将硬件相关数据(如几个SPI,每个SPI控制器的寄存器地址等等)统一按设备树的结构独立于内核进行配置和修改,这里需要了解的就是设备树语法知识。有了设备树文件后,如何让内核代码读取这些信息,进行板级初始化,Linux的做法是编译成DTB文件,然后在内核启动时进行解析,逐一获取硬件数据。
为什么要引入设备树,《原子嵌入式Linux驱动开发详解与实战》举了个很有意思的案例,大概的意思就是之前Linus对ARM社区合并进来的各类驱动都进主线比较头疼,因为各类设备的各种驱动merger后,直接导致Kernel日趋臃肿,而且臃肿的速度越来越快。目前的RTOS大部分都是这种,把各种BSP驱动加进main line,然后用特定的宏确定是否需要编译。
同样的,当 Linux 之父 linus 看到 ARM 社区向 Linux 内核添加了大量“无用”、冗余的板级信息文件,不禁的发出了一句“This whole ARM thing is a fcking pain in the ass”。从此以后 ARM 社区就引入了 PowerPC 等架构已经采用的设备树(Flattened Device Tree),将这些描述板级硬件信息的内容都从 Linux 内中分离开来,用一个专属的文件格式来描述,这个专属的文件就叫做设备树,文件扩展名为.dts。 一个 SOC 可以作出很多不同的板子,这些不同的板子肯定是有共同的信息, 将这些共同的信息提取出来作为一个通用的文件,其他的.dts 文件直接引用这个通用文件即可,这个通用文件就是.dtsi 文件,类似于 C 语言中的头文件。一般.dts 描述板级信息(也就是开发板上有哪些 IIC 设备、 SPI 设备等), .dtsi 描述 SOC 级信息(也就是 SOC 有几个 CPU、主频是多少、各个外设控制器信息等)。
DTS、DTB、DTC的关系
1、DTS是设备树的源文件,.dts相当于DTS源码文件;
设备树是采用树形结构来描述板子上的设备信息的文件,每个设备都是一个节点,叫做设备节点,每个节点都通过一些属性信息来描述节点信息,属性就是键—值对。
/是根节点,每个设备树文件只有一个根节点, aliases、cpus 和intc是三个子节点。
2、DTB是DTS编译后得到的二进制文件;
通过make dtbs编译所有的dts文件。
3、DTC是DTS的编译工具,将DTS文件编译成DTB文件,源码在内核的scripts/dtc目录下面,scripts/dtc/Makefile 文件内容:
最后来一个/proc/device-tree的信息:
ubuntu@bionic-dev64:/proc/device-tree$ ls
'#address-cells' mmc@30b60000
alias_create_phandles model
aliases name
anatop@30360000 ocotp-ctrl@30350000
backlight-mipi pcie@0x33800000
bt-rfkill pinctrl@30330000
busfreq pmu
caam@30900000 power-domains
caam_secvio psci
caam-sm@00100000 pwm@30660000
caam-snvs@30370000 pwm@30670000
chosen pwm@30680000
clock-controller@30380000 pwm@30690000
clocks regulator-usdhc2-vqmmc
compatible regulator-vref-0v9
cpus regulator-vref-1v8
csi1_bridge@32e20000 regulator-vref-2v5
ddr_pmu@3d800000 regulator-vref-3v3
display-gpr@32e28000 regulator-vref-5v
display-subsystem regulator-wlan-vmmc
dma_cap reserved-memory
dma-controller@302b0000 sai@30010000
dma-controller@302c0000 sai@30020000
dma-controller@30bd0000 sai@30030000
ecspi@30820000 sai@30050000
ecspi@30830000 sai@30060000
ecspi@30840000 serial@30860000
ethernet@30be0000 serial@30880000
flexspi@30bb0000 serial@30890000
gpc@303a0000 serial@30a60000
gpio@30200000 '#size-cells'
gpio@30210000 snvs@30370000
gpio@30220000 sound-wm8960
gpio@30230000 spdif@30090000
gpio@30240000 src@30390000
gpu@38000000 __symbols__
i2c@30a20000 thermal-zones
i2c@30a30000 timer
i2c@30a40000 timer@306a0000
i2c@30a50000 tmu@0x30260000
imx_ion usb@32e40000
imx_rpmsg usb@32e50000
interrupt-controller@38800000 usbmisc@32e40200
interrupt-parent usbmisc@32e50200
iomuxc-gpr@30340000 usbphynop1
lcdif@32E00000 usbphynop2
memory@40000000 vpu_g1@38300000
micfil@30080000 vpu_g2@38310000
mipi-cmds-ltk080a60a004t vpu_h1@38320000
mipi_csi@32e30000 wdog@30280000
mipi_dsi@32E10000 wdog@30290000
mmc@30b40000 wdog@302a0000
mmc@30b50000