设备树DTS 学习:1-有关概念

背景

设备树在Linux驱动开发中是一种比较常用的架构。

参考:《设备树DTS使用总结》《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

设备树的编译、加载过程图:

graph LR DTS,DTSI--> |DTC| DTB DTB--> |Bootloader| kernel

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。

设备树原理

  1. 首先用户要了解硬件配置和系统运行参数,并把这些信息组织成Device Tree source file。
  2. 通过DTC(Device Tree Compiler),可以将这些适合人类阅读的Device Tree source file变成适合机器处理的Device Tree binary file(也叫DTB,device tree blob)。
  3. 在系统启动的时候,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。
  4. 本质上,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

明确了设备树的各种基础概念以后,接下来,我们就来了解实际开发中设备树的语法,以及编写设备树)。

posted @ 2020-01-18 09:56  schips  阅读(4116)  评论(0编辑  收藏  举报