设备树(Device Tree)是一种用来描述系统硬件的数据结构,一些硬件设备设计机制就是可被系统发现的(如PCI Express或者USB总线),而有一些则不是(尤其是内存映射外设)。对于后一种情况,不同于X86架构系统采用BIOS和操作系统沟通硬件拓扑信息,ARM Linux通常情况是将硬件设备描述硬编码到系统内核(Linux Kernel)中,但由于ARM嵌入式设备的多样和离散性,即便如此也不能保证覆盖到所有设备,而且长久以来给ARM Linux内核代码维护造成了很大负担;基于这种情况,设备树的概念就被提出,将ARM SOC和板卡硬件平台描述信息从内核独立出来成为设备树文件,通过bootloader传递给内核来识别当前平台设备并加载相应的资源和驱动,这样就把ARM嵌入式Linux 内核统一起来,更好的利于内核维护,而对于广泛的ARM嵌入式设备系统维护和迁移也更方便和有效率。
设备树机制从Linux 内核3.2 版本左右开始采用,其不仅可以定义ARM SoC内部内存映射外设,还可以定义整个板卡,下面就以Toradex Colibri VF61计算机模块搭配Colibri Eva Board为例来展示设备树的具体应用,另外关于设备树的更深入介绍,请参考这里。
2). 设备树文件说明
Toradex ARM计算机模块工业产品级Embedded Linux源代码下载及编译指南请见这里,其中设备树文件位于Kernel 源代码 arch/arm/boot/dts/ 目录下。
产品系列 | SoC | Image 版本 | SoC 级别 | 模块级别 | Eva Board级别 |
Colibri VF50 | NXP/Freescale Vybrid | V2.3Beta5 onwards | vf500.dtsi | vf500-colibri.dtsi | vf500-colibri-eval-v3.dts |
Colibri VF61 | NXP/Freescale Vybrid | V2.3Beta5 onwards | vf610.dtsi | vf610-colibri.dtsi | vf610-colibri-eval-v3.dts |
Colibri iMX6DL/S | NXP/Freescale i.MX6 | all compatible | imx6q.dtsi | imx6qdl-colibri.dtsi | imx6dl-colibri-eval-v3.dts |
Apalis iMX6Q/D | NXP/Freescale i.MX6 | V2.3Beta3 onwards | imx6q.dtsi | imx6qdl-apalis.dtsi | imx6q-apalis-eval.dts |
设备树通常由多级别的多个设备树文件构成,一个设备树文件(dts 和dtsi)可以包含另外一个可包含设备树文件(dtsi),如一个板卡级设备树文件(dts)一般会包含其所使用的SoC级别的设备树文件(dtsi)。如上图所示,为了支持Toradex产品,定义了三个级别的设备树文件:载板级别,模块基本以及SoC级别,这些区别也体现在了设备树文件的命名上面。
载板级别的设备树文件(如vf610-colibri-eval-v3.dts)定义自Colibri Eva Board载板,但基于Colibri模块的标准定义,同样也兼容于其他Colibri载板(如Iris载板);不过如果用户针对自己应用定制了载板,则需要对应定制化设备树文件以便使能非默认定义功能设备(如第二个网口)或者关闭一些无用的设备。
设备树文件(dts)最后要被编译成设备树二进制文件(dtb)以供Linux 内核启动加载所使用,所需的编译器也都集成在Linux源文件里面可以直接调用,从后面的示例可以看到具体的编译方法。
设备树文件的基本单元是node,一个设备树文件只能有一个root node (/),其他node按照parent/child node以树状结构分布,每个node里面包含一些property/value来描述该node特性,如下面是一个UART 设备的描述;另外低级别设备树文件的定义可以在更高级别的设备树文件中重新定义或者更改,最后生成的二进制文件以最后一次定义为准,因此我们定制化设备树文件时候通常只定制修改最高级别的载板级设备树文件即可;更详细的关于设备树文件语法的说明请见这里。
3). 定制设备树文件
本文以Colibri VF61计算机模块和Eva board载板为例,定制设备树文件以使能GPIO和CAN bus。Colibri Vybird系列产品设备树文件的架构如下图所示:
a). 创建新的载板级别设备树文件,这里为了方便直接复制vf610-colibri-eval-v3.dts
----------------------------------------------------------------------------------------
$ cp arch/arm/boot/dts/vf610-colibri-eval-v3.dts arch/arm/boot/dts/vf610-colibri-my-carrier.dts
----------------------------------------------------------------------------------------
b). 编辑设备树文件vf610-colibri-my-carrier.dts,将默认配置为PWM设备管脚配置为GPIO
----------------------------------------------------------------------------------------
$ vi vf610-colibri-my-carrier.dts
-------------------
//添加下面内容于设备树文件中
c). 配置编译环境并编译新的设备树文件
./ 安装交叉编译Tool Chain,请从这里下载
----------------------------------------------------------------------------------------
$ tar xvf gcc-linaro-4.9-2014.11-x86_64_arm-linux-gnueabihf.tar.xz
$ ln -s gcc-linaro-4.9-2014.11-x86_64_arm-linux-gnueabihf gcc-linaro
----------------------------------------------------------------------------------------
./ 配置环境变量
----------------------------------------------------------------------------------------
$ export ARCH=arm
$ export PATH=~/gcc-linaro/bin/:$PATH
$ export CROSS_COMPILE=arm-linux-gnueabihf-
----------------------------------------------------------------------------------------
./ 修改arch/arm/boot/dts/Makefile文件, 插入"vf610-colibri-my-carrier.dtb"
----------------------------------------------------------------------------------------
dtb-$(CONFIG_SOC_VF610) += \
vf500-colibri-eval-v3.dtb \
vf610-colibri-eval-v3.dtb \
vf610-colibri-my-carrier.dtb \
vf500-colibri-dual-eth.dtb \
vf610-colibri-dual-eth.dtb \
vf610-cosmic.dtb \
vf610-twr.dtb
----------------------------------------------------------------------------------------
./ 编译设备树文件,源代码根目录linux-toradex下,生成的文件可以在arch/arm/boot/dts/下找到
----------------------------------------------------------------------------------------
$ make colibri_vf_defconfig
$ make dtbs
----------------------------------------------------------------------------------------
4). 部署新的设备树文件并测试
a). 将新的设备树文件"vf610-colibri-my-carrier.dtb"放置到目标板Colibri VF61 Linux系统 /boot目录下
b). 如下修改目标板 uboot环境变量
----------------------------------------------------------------------------------------
$ setenv fdt_board my-carrier
$ saveenv
----------------------------------------------------------------------------------------
c). 重启后则系统加载新的设备树文件
下面两个截图分别是更改前和更改后使用Toradex提供的GPIOConfig工具对PWM对应管脚进行查看,可以看到由原来的PWM属性变成了GPIO,修改成功后则可以按照这里的说明直接调用GPIO使用。
d). 对于CAN,Colibri VF61支持两个CAN接口,CAN0和CAN1,在设备树中使能CAN设备示例如下
./ 编辑vf610-colibri-my-carrier.dts,添加下面内容
./ 和上述方法一样重新编译设备树文件后部署,然后就可以在系统中调用CAN了,更详细的说明可以参考这里。