Part 01
● Linux设备树机制的介绍 ●
1.1 概念
设备树(device tree)是一种描述硬件资源的数据结构,起源于Open Firmware(OF:开源固件)。在Linux kernel v2.6之前的版本,关于ARM架构的板级硬件资源均通过.c和.h文件写“死”在arch/arm/plat-xxx和arch/arm/mach-xxx目录下,在开发一款设备时,Linux kernel中充斥着许多无用的硬件信息,不利于阅读和维护。在Linux ARM kernel v3.x之后正式引入设备树机制,主要是为减少这类无用的硬件板级信息被写入Linux kernel中污染内核,有了设备树,则可通过它来将所需的硬件信息传递给Linux kernel。
1.2 组成
设备树主要包含dts(device tree source,源文件)、dtc(device tree compiler,编译工具)和dtb(device tree blob,二进制文件)。
dts 是设备树描述的源文件,在ARM架构下,一个dts对应一个设备,一般位于arch/arm(64)/boot/dts目录下,该文件一般会有包含对应名称的.dtsi文件,类似于c语言的头文件,主要是一些SOC的宏定义共性部分。
dtc 是设备树的编译工具,类似于gcc等编译器,但与gcc不同的是dtc无需外部安装,是由内核自带的。可以将.dts文件编译成.dtb文件。
dtb 是设备树二进制文件,可被Linux kernel识别解析,也可被bootloader解析。
dtbo 是overlay编译出来的二进制文件。
dts、dtc和dtb三者间的关系如下图:
Part 02
● 设备树框架和dts文件语法格式 ●
2.1 设备树基本框架
设备树文件基本结构主要有以下几部分,其形式有点类似xml文件。
- 单根节点(root):/
- 节点名称:图中的"node1"和"node2"
- 子节点:"child-node1"和"child-node2"
- 节点地址:node@xxx
- 属性(property):是一组键值对,包括属性名称(property name)和属性值(property value)
- 标签(label,可选项)
https://elinux.org/Device_Tree_Usage#Basic_Data_Format
值得注意的是,“/”是根节点,每个设备树文件仅有一个,当在设备树中发现有多个根节点时,在编译过程中这些根节点会合并成一个。
2.2 dts文件语法格式
与c语言类似,dts同样支持头文件,其头文件扩展名为.dtsi,一般通过#include xxx来引用。
例如,以全志H616这款芯片为例,基于Linux v4.9版本的orangepi开发板的时钟节点(部分)如下:
上述中,特别重要的compatible属性,它可以以“,”格式指定名称的优先选择。设备树中每个代表设备的节点都要有一个compatible属性,它是OS用于决定绑定到设备驱动的关键特征。
Part 03
● 设备树的修改与内核编译安装 ●
在编写模块的驱动程序时,为不影响内核结构,通常在外部目录下建立一个用于存放编写的驱动源码和编译生成的.ko的文件夹,生成的.ko可以在系统启动后单独加载运行,且无需和内核一起编译,方便更新。其流程一般为:makefile文件编写,接着进行驱动源码编写(可找优秀的架构进行修改,填充细节,如compatible,读、写操作等),然后编译生成.ko文件,进一步修改与单板相关的设备树文件(.dts),在.dts文件中添加或删除相应的设备节点信息,最后编译整个内核文件,当内核编译完成后,使用如下命令卸载旧版本的内核与安装新版本内核:
重启单板后,用uname -a 命令查看内核信息,在新编译的内核上,用insmod 命令将生成的.ko模块加载上,cat 命令查看设备节点信息。
需要注意的是,设备树的使用需要在编译kernel时做好对应的配置,还需bootloader支持,否则也无法将数据结构传参给kernel。