Linux设备树的出现
DTS (Device Tree Source)设备树源码,Device Tree是一种描述硬件的数据结构,源于 OpenFirmware (OF)。
往Linux较前的版本看看
在Linux 2.6中,arch/arm/plat-xxx 和 arch/arm/mach-xxx 中充斥着大量的垃圾代码,相当多数的代码只是在描述板级细节,而这些板级细节对于内核来讲,不过是垃圾,如板上的platform设备、resource、i2c_board_info、spi_board_info以及各种硬件platform_data。
在Linux3.x版本后,arch/arm/plat-xxx 和 arch/arm/mach-xxx 中,描述板级细节的代码(比如platform_device、i2c_board_info等)被大量取消,取而代之的是设备树,其目录位于 arch/${ARCH}/boot/dts。设备树最早用于PowerPC等其他体系架构,到现在,很多架构都支持设备树。
所以DTS的出现是为了解决当初老版本内核中塞入了许多冗余的板级细节代码影响迭代的问题。设备信息由原来的从内核中hardcode的形式转移到从bootloader中以一个二进制的形式传递给内核。
Linux设备树的相关名词
在学习前最好知道一些名词,毕竟我大学学习ARM前,老师也先介绍了一堆名词,毕竟简写在计算机领域可不要太常见了,冷不丁碰着看不懂,那不就G了?反正也不多,就先列着吧。
- DT : 设备树 (Device Tree)
- FDT : 扁平化设备树 (Flattened Device Tree)
- OF : 一个固件标准的名称,目前以濒临淘汰 (Open Firmware)
- DTS : 设备树源文件 (Device Tree Source)
- DTSI : 设备树源文件包含文件 简易理解为扩展文件 (Device Tree Source Include)
- DTB : 设备树二进制文件 (Device Tree Blob)
- DTC : 设备树编译器 (Device Tree Compiler)
设备树加载流程
1、首先开发人员需要了解硬件配置以及系统运行的参数,并把这些信息整合成DTS文件或者扩展出DTSI
2、通过DTC,可以将这些适合人类阅读的DTS或DTSI文件,变成适合机器处理的DTB
3、在系统启动的时候,boot program(例如:firmware、bootloader)可以将保存在flash中的DTB copy到内存(或通过bootloader的交互式命令加载DTB,或者firmware可以探测到device的信息,组织成DTB保存在内存中),并把DTB的起始地址传递给client program(例如OS kernel,bootloader或者其他特殊功能的程序)。对于计算机系统(computer system),一般是 firmware(UEFI or BIOS)->bootloader->OS ,对于嵌入式系统,一般是 bootloader->OS。
设备树相关文件介绍
与设备树有关的文件一共有3种: dts、dtsi与dtc
一般dts以及dtsi这两种文件存储在 /arch/${ARCH}/boot/dts
比如最近我工作中遇到的SDK,dts源文件存储在 qsdk/qca/src/linux-5.4/arch/arm64/boot/dts/qcom
为什么需要dtsi
既然dts已经描述了硬件设备信息,为什么还需要一个dtsi?
如果学习过C或者C++你会发现,当工程量打了之后一个.c 或者 .cpp是不够的,必然会有头文件出现,如.h、.hpp。这些文件都是为了封装反复使用的函数,减少工程冗余的。
在设备树里,dtsi出现的理由也类似,dts属于板级定义文件,dtsi则属于SOC级定义文件。每一个电路板都有一个自己的dts,这些dts势必会存在许多共同部分,为了减少代码冗余,设备树将这些共同部分提炼保存在.dtsi文件中,供不同的dts共同使用。
dtsi的使用方法,类似于C语言的头文件,在dts文件中需要进行include .dtsi文件。当然,dtsi本身也支持include 另一个dtsi文件。
DTB文件的制作
在前面的部分已经提到过加载流程,其中出现了DTC这么一个词,这个就是设备树的编译器。
它负责将高级语言的源码,编译成机器语言即二进制文件。
使用范例:
dtc -I dts -O dtb -o B_dtb.dtb A_dts.dts # 把A_dts.dts编译生成B_dtb.dtb
dtc -I dtb -O dts -o A_dts.dts A_dtb.dtb # 把A_dtb.dtb反编译生成为A_dts.dts
详细信息可以使用 dtc -h 查看,以下是案例,随着版本迭代,不一定相同。
Usage: dtc [options] <input file>
Options: -[qI:O:o:V:d:R:S:p:a:fb:i:H:sW:E:@AThv]
-q, --quiet
Quiet: -q suppress warnings, -qq errors, -qqq all
-I, --in-format <arg>
Input formats are:
dts - device tree source text
dtb - device tree blob
fs - /proc/device-tree style directory
-o, --out <arg>
Output file
-O, --out-format <arg>
Output formats are:
dts - device tree source text
dtb - device tree blob
asm - assembler source
-V, --out-version <arg>
Blob version to produce, defaults to 17 (for dtb and asm output)
-d, --out-dependency <arg>
Output dependency file
-R, --reserve <arg>
Make space for <number> reserve map entries (for dtb and asm output)
-S, --space <arg>
Make the blob at least <bytes> long (extra space)
-p, --pad <arg>
Add padding to the blob of <bytes> long (extra space)
-a, --align <arg>
Make the blob align to the <bytes> (extra space)
-b, --boot-cpu <arg>
Set the physical boot cpu
-f, --force
Try to produce output even if the input tree has errors
-i, --include <arg>
Add a path to search for include files
-s, --sort
Sort nodes and properties before outputting (useful for comparing trees)
-H, --phandle <arg>
Valid phandle formats are:
legacy - "linux,phandle" properties only
epapr - "phandle" properties only
both - Both "linux,phandle" and "phandle" properties
-W, --warning <arg>
Enable/disable warnings (prefix with "no-")
-E, --error <arg>
Enable/disable errors (prefix with "no-")
-@, --symbols
Enable generation of symbols
-A, --auto-alias
Enable auto-alias of labels
-T, --annotate
Annotate output .dts with input source file and line (-T -T for more details)
-h, --help
Print this help and exit
-v, --version
Print version and exit