背景
設備樹在Linux驅動開發中是一種比較常用的架構。
Linux設備樹 介紹
DTS即Device Tree Source 設備樹源碼, Device Tree是一種描述硬件的數據結構,它起源於 OpenFirmware (OF)。
所以我們看到的一些of函數,便是代表
OpenFirmware
的縮寫。
在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
。設備樹(Dervice tree source) 最早用於PowerPC等其他體系架構,到現在,很多架構都支持設備樹。
對ARM平台的相關code做出如下相關規范調整,這個也正是引入DTS的原因。
1、ARM的核心代碼仍然保存在arch/arm
目錄下
2、ARM SoC core architecture code保存在arch/arm
目錄下
3、ARM SOC的周邊外設模塊的驅動保存在drivers
目錄下
4、ARM SOC的特定代碼在arch/arm/mach-xxx
目錄下
5、ARM SOC board specific
的代碼被移除,由DeviceTree機制來負責傳遞硬件拓撲和硬件資源信息。
本質上,Device Tree改變了原來用hardcode方式將HW 配置信息嵌入到內核代碼的方法,改用bootloader傳遞一個DB的形式。
開放固件設備樹---Open Firmware Device Tree
- Device Tree可以描述的信息包括:CPU的數量和類別、內存基地址和大小、總線和橋、外設連接、中斷控制器和中斷使用情況、GPIO控制器和GPIO使用情況、Clock控制器和Clock使用情況。
- 設備樹信息被保存在一個ASCII 文本文件中,適合人類的閱讀習慣,類似於xml文件, 在ARM Linux中,一個.dts文件對應一個ARM的machine放置在內核的
arch/${ARCH}/boot/dts/
- 設備樹是一種數據結構,用於描述設備信息的語言,具體而言,是用於操作系統中描述硬件,使得不需要對設備的信息進行硬編碼(hard code)
- Device Tree由一系列被命名的結點(node)和屬性(property)組成,而結點本身可包含子結點。所謂屬性,其實就是成對出現的key和value
- 設備樹源文件dts被編譯成dtb二進制文件,在bootloader運行時傳遞給操作系統,操作系統對其進行解析展開(Flattened),從而產生一個硬件設備的拓撲圖有了這個拓撲圖,在編程的過程中可以直接通過系統提供的接口獲取到設備樹中的節點和屬性信息
設備樹有關名詞解釋:
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
設備樹的編譯、加載過程圖:
linux內核對硬件的描述方式
- 在以前的內核版本中:
1)內核包含了對硬件的全部描述;
2)bootloader會加載一個二進制的內核鏡像,並執行它,比如uImage或者zImage;
3)bootloader會提供一些額外的信息,成為ATAGS,它的地址會通過r2寄存器傳給內核;
ATAGS包含了內存大小和地址,kernel command line等等;4)bootloader會告訴內核加載哪一款board,通過r1寄存器存放的machine type integer;
5)U-Boot的內核啟動命令:bootm
- 現今的內核版本使用了Device Tree:
1)內核不再包含對硬件的描述,它以二進制的形式單獨存儲在另外的位置:the device tree blob
2)bootloader需要加載兩個二進制文件:內核鏡像和DTB
內核鏡像仍然是uImage或者zImage;
DTB文件在arch/arm/boot/dts中,每一個board對應一個dts文件;3)bootloader通過r2寄存器來傳遞DTB地址,通過修改DTB可以修改內存信息,kernel command line,以及潛在的其它信息;
4)不再有machine type;
5)U-Boot的內核啟動命令:
bootm <kernel img addr> - <dtb addr>
有些bootloader不支持Device Tree,或者有些專門給特定設備寫的bootloader版本太老了,也不包含。
為了解決這個問題,CONFIG_ARM_APPENDED_DTB被引進,會告訴內核,在緊跟着內核的地址里查找DTB文件;由於沒有built-in Makefile rule來產生這樣的內核,因此需要手動操作:
cat arch/arm/boot/zImage arch/arm/boot/dts/myboard.dtb > my-zImage mkimage ... -d my-zImage my-uImage
另外,CONFIG_ARM_ATAG_DTB_COMPAT選項告訴內核去bootloader里面讀取ATAGS,並使用它們升級DT。
設備樹原理
- 首先用戶要了解硬件配置和系統運行參數,並把這些信息組織成Device Tree source file。
- 通過DTC(Device Tree Compiler),可以將這些適合人類閱讀的Device Tree source file變成適合機器處理的Device Tree binary file(也叫DTB,device tree blob)。
- 在系統啟動的時候,boot program(例如:firmware、bootloader)可以將保存在flash中的DTB copy到內存(或通過bootloader的交互式命令加載DTB,或者firmware可以探測到device的信息,組織成DTB保存在內存中),並把DTB的起始地址傳遞給client program(例如OS kernel,bootloader或者其他特殊功能的程序)。對於計算機系統(computer system),一般是firmware->bootloader->OS,對於嵌入式系統,一般是bootloader->OS。
- 本質上,Device Tree改變了原來用hardcode方式將HW 配置信息嵌入到內核代碼的方法,改用bootloader傳遞一個DB的形式。
設備樹有關文件介紹
與設備樹有關的文件一共有3種: dts、dtsi與dtc
1) DTS和DTSI(Source,Include 源文件)
.dts文件是一種ASCII文本對Device Tree的描述,放置在內核的/arch/${ARCH}/boot/dts目錄。一般而言,一個.dts文件對應一個ARM的machine。
由於一個SOC可能有多個不同的電路板(.dts文件為板級定義, .dtsi文件為SoC級定義),而每個電路板擁有一個 .dts。這些dts勢必會存在許多共同部分,為了減少代碼的冗余,設備樹將這些共同部分提煉保存在.dtsi文件中,供不同的dts共同使用。.dtsi的使用方法,類似於C語言的頭文件,在dts文件中需要進行
include .dtsi
文件。當然,dtsi本身也支持include 另一個dtsi文件。
DTS的語法結構
每個設備樹文件都有一個根節點/
,每個設備視為一個節點。節點間可以嵌套,形成父子關系,這樣就可以方便的描述設備間的關系。
- 1個root結點"/"
- root結點下面含一系列子結點
- 子結點下又含有一系列子結點
- 各結點都有一系列屬性,屬性類型有
- 空屬性:empty-property
- 字符串屬性:string-property
- 字符串列表屬性:string-list-property
- Cells(u32整型)屬性:cell-property
- 二進制數屬性:binary-property
2) DTC (Compiler 編譯工具)
DTC為編譯工具,dtc編譯器可以把dts文件編譯成為dtb,也可把dtb編譯成為dts文件。
在3.x內核版本中,DTC的源碼位於內核的scripts/dtc目錄,編譯以后的工具在scripts/dtc/dtc
中,內核選中CONFIG_OF (即Open Firmware),編譯內核的時候,主機可執行程序DTC就會被編譯出來。 即scripts/dtc/Makefile中
獲取DTC的2種方式
- 在linux下,
make dtbs ,這里的s代表復數
可單獨編譯dtb。
hostprogs-y := dtc
always := $(hostprogs-y)
在內核的arch/${ARCH}/boot/dts/Makefile中,若選中某種SOC,則與其對應相關的所有dtb文件都將編譯出來。以下截取了Makefile其中一部分。
ifeq ($(CONFIG_OF),y) dtb-$(CONFIG_ARCH_TEGRA) += tegra20-harmony.dtb \ tegra30-beaver.dtb \ tegra114-dalmore.dtb \ tegra124-ardbeg.dtb
- 在系統中安裝,例如ubuntu:
sudo apt-get install device-tree-compiler
,此后輸入dtc
使用即可
3) DTB (Blob 二進制文件)
DTC編譯.dts生成的二進制文件(.dtb),bootloader在引導內核時,會預先讀取.dtb到內存,進而由內核解析。
dtb文件可以由dtc
單獨進行編譯,編譯命令格式如下:
dtc [-I input-format] [-O output-format][-o output-filename] [-V output_version] input_filename
參數說明(由 man dtc
得到):
NAME
dtc - Device Tree Compiler
SYNOPSIS
/usr/bin/dtc [options] <input file>
DESCRIPTION
Device Tree Compiler, dtc, takes as input a device-tree in a given format and outputs a device-tree in another for‐
mat for booting kernels on embedded systems. Typically, the input format is "dts", a human readable source format,
and creates a "dtb", or binary format as output.
OPTIONS
-h Display help text.
-q Quiet:
-q - Suppress warnings.
-qq - Suppress errors.
-qqq - Suppress all.
-I <input format>
Input formats are:
dts - device tree source text
dtb - device tree blob
fs - /proc/device-tree style directory
-o <output file>
Dump the result into a file, instead of stdout.
-O <output format>
Output formats are:
dts - device tree source text
dtb - device tree blob
asm - assembler source
-V <output version>
Blob version to produce. The default is 17 (only relevant for dtb and asm output).
-d <output dependency file>
-R <number>
Make space for <number> reserve map entries (only relevant for dtb and asm output).
-S <bytes>
Make the blob at least <bytes> long (extra space).
-p <bytes>
Add padding to the blob of <bytes> long (extra space)
-b <number>
Set the physical boot CPU.
-f Force - try to produce output even if the input tree has errors.
-s Sort nodes and properties before outputting (only useful for comparing trees)
-v Print DTC version and exit.
-H <phandle format>
phandle formats are:
legacy - "linux,phandle" properties only
epapr - "phandle" properties only
both - Both "linux,phandle" and "phandle" properties
dtc命令的使用范例
(1) dts編譯生成dtb
./scripts/dtc/dtc -I dts -O dtb -o B_dtb.dtb A_dts.dts # 把A_dts.dts編譯生成B_dtb.dtb
(2) dtb編譯生成dts(反匯編dtb)
./scripts/dtc/dtc -I dtb -O dts -o A_dts.dts A_dtb.dtb # 把A_dtb.dtb反編譯生成為A_dts.dts
明確了設備樹的各種基礎概念以后,接下來,我們就來了解實際開發中設備樹的語法,以及編寫設備樹)。