DTS github:http://devicetree.org/Device_Tree_Usage
翻译版本:devicetree-specification-v0.2.pdf
"Open Firmware Device Tree"或者简单设备树,是一种描述硬件的一种数据结构和语言。特别的是,使用DTS描述操作系统只读的硬件信息,因此操作系统中不需要硬编码描述设备信息。
结构上,DT是一种树形结构,以node组成的非循环的图。每一个node都有多个属性和属性值。机制确保一个node和其他node任意的关联。
为了初始化和启动电子计算机系统,软件模块相互交互。在通过操作系统、bootloader、管理程序等控制之前,固件运行在一个初始化层次比较低的硬件系统。按顺序,加载bootloader,管理程序转移控制权给操作系统。一般情况下,统一的接口和约定促进软件模块间的交互。通常启动程序涉及的模块为初始化阶段和启动运行其他软件模块的部分软件。被启动运行的部分软件被称为客户端程序。启动程序包含:固件(firmware)、bootloaders、管理程序。客户端软件包含:bootloaders、管理程序、操作系统、其他特殊需求程序。一部分程既是启动程序也是客户程序,如管理程序。
DTS规范定义了从启动程序到客户程序的完整接口,使最小系统需求(减少代码冗余)和系统紧密结合,促进了广泛的多样化系统开发。
满足
DTS规范针对的是嵌入式系统。一个典型的嵌入式系统包含系统硬件、操作系统、应用软件,这些组成部分都是被客制化设计,满足和完成特定工作。不同于通用的电子计算机系统,被设计为包含多样软件和多个I/O设备,满足用户不同的自定义需求。嵌入式系统包含一些其他特点:
DTS和开放固件标准IEEE 1275(IEEE Standard for Boot (Initialization Configuration) Firmware: Core Requirements and Practices [IEEE1275])松散耦合的。
最初的 IEEE 1275 和它的的验证版本,如 CHRP [CHRP] and PAPR [PAPR] ,旨在解决通用电子计算机的一些问题,如单个操作系统软件可以在同一个家族不同的计算机上运行;从用户I/O设备中按照操作系统等问题。
由于嵌入式系统的特性,通用电子计算机有的问题在嵌入式不存在。因此,IEEE 1275 规范中的一些功能在DTS中可以忽略,包含以下:
IEEE-1275 被保留的是利用设备数,在启动程序中描述和与传递系统硬件信息给客户程序。如此,排除了客户程序中对系统硬件的硬编码描述。
DTS规范部分接替了 ePAPR [EPAPR] 规范。ePAPR 文档描述了怎么通过 PowerISA使用设备树,以及覆盖了DTS规范的基础章节和bindings部分。
DTS支持32位、64位CPUs。
AMP 非对称多处理器。计算机中cpu被分为不同的组,每个组运行不同的操作系统。cpus可能是系统同的也可能是不同的。
boot CPU 启动程序运行和指向客户端软件,并启动客户端软件的第一个CPU。
Book III-E 嵌入式环境。启动指令中管理指令的一部分。关联启动过程一些工具的实现。
启动程序 初始化系统并启动客户端程序,是一个软件组件。包含: firmware, bootloaders, and hypervisors。
客户端程序 包含应用和操作系统软件,被启动程序启动。包含:bootloaders(开机引导程序), hypervisors(管理程序), operating systems(操作系统), and special purpose programs(特殊作用的程序)。
cell 一个32bits的信息单元
DMA 直接内存访问
DTB 被编译出来的设备树二进制文件。
DTC 设备数程序的编译器。编译DTS文件为DTC文件。
effective address 有效地址。被处理器计算出来的存储地址或者其他指令地址。
physical address 物理地址。被处理器用来访问外部设备,典型的设备,如内存管理器。
Power ISA 启动指令集架构
interrupt specifier 描述一个中断的属性值。包含的基本数据是:终端号、敏感和触发机制。
secondary CPU cpu集合中非boot CPU。客户端程序开始运行时使用
SMP 对称多处理器。一种计算机架构,有多个相同的cpu,多个cpu可共享内存、IO等。
SoC 基于一个芯片的系统。一个计算机芯片集成了一个或多个cpu,以及一些可编程外围设备。
unit address 一个节点的相对于父节点的地址空间。
quiescentCPU 静默CPU。不可以和标准指令的cpu进行交互,也不可被其他运行的CPU用标准指令影响其状态。除非使用明确的方法启动或者重启该静默CPU。
DTS规范详述一个描述系统硬件的规范。启动程序加载设备数信息到客户端程序的内存地址中并传递执行设备数信息的地址给客户端程序。
设备树是一个树形数据结构。每一个节点都有多个键值对(name-value),除了root节点,其他节点都有一个确定的父节点。
一个服从DTS规范的设备树描述的设备信息一定不可以被客户端程序动态检测到。例如:PCI总线探查和检测一个关联的设备,这不需要设备数描述;但是,一个PCI host bridge必须被描述为一个设备节点。
1、节点定义
一个设备树节点定义方式:
node-name@unit-address
node-name指定一个节点的名称,有1到31个字符组成。可用字符如下:
名称必须以一个小写或大写的字符开头。
unit-address指定在总线类型的位置,包含一个或多个上表中的ASCII字符。如果描述的节点有reg属性值,unit-address必须是reg的第一个地址;如果没有reg属性,unit-address可以被忽略,禁用名称区别设备数同一层的其他节点。根节点没有名称和地址。节点例子如下:
节点名称应当通用,能直接反应设备功能。在规范中已定义了一些通用节点,可参考使用。
2、节点路径
设备数的每一个节点,基于根节点的路径,这设备树中是唯一的。比如
/node-name-1/node-name-2/node-name-N
如果节点的单元地址被忽略了,节点路径是不明确的。这种路径传递给客户端程序,客户端程序的行为是不确定的。
3、属性
每一个节点有多个属性描述节点特性。属性有属性名称和属性值组成。
属性名称由下表中1-31个字符组成
非标准属性名称,应该有一个唯一的前缀,前缀可以是公司、组织等的简称,如:
fsl,channel-fifo-len
ibm,ppc-interrupt-server#s
linux,network-index
前缀和名称用逗号隔开。
属性值是一个有0个或多个字节的信息。如果属性值是empty,该属性仅传送true-false信息,这种情况,值是否为empty,都足以描述属性了。下表是常用的属性值集合:
4、标准属性
节点描述,可以便准和非标准属性额外声明节点需求和约束条件。
compatible
Value type:
描述:指定设备程序模块。用于在客户端程序为设备选择对应的驱动。该属性值是一个非null终止的字符串集,描述等级从最匹配到通用,描述设备使用驱动从匹配到相似匹配,因此可以存在一个驱动匹配多个设备。
属性值格式"manufacturer,model",manufacturer描述设备制造商,model描述设备型号。例如:
compatible = "fsl,mpc8641", "ns16550";
在该例中,如果ns16550的驱动找不到,就会使用ns16550的驱动。
model
Value type:
描述:说明设备制造商制造该设备的设备型号。使用方式同属性compatible。
phandle
Value type:
描述:定义节点的设备树中唯一的数字标识。在另外一个节点中使用该数字标识,指向该节点。
例如:
pic@10000000 {
phandle = <1>; interrupt-controller;
};
一个phandle值被定义,另外一个节点使用该节点
nother-device-node {
interrupt-parent = <1>;
};
注意: 很多DTS中将不再清楚明描述phandle属性。DTC工具在编译时,会自动的添加phandle到DTB中。
device_type(deprecated)
Value type:
描述:该属性实在 IEEE 1275中使用,描述设备的FCode程序模型。由于DTS没有FCode,因此该属性不推荐使用。该属性仅仅被使用在cpu、memory节点使用 IEEE 1275–derived 描述的设备树中。
在这里仅列出几个常用的标准属性,其他属性可以在DTS的github中下载文档,自行查询。
1、概述
DTS在Open Firmware Recommended Practice采用中断树描述中断。在设备树中存在一个逻辑上的中断树,代表层级和硬件层面的中断路由。
物理连接中断源和中断控制器,在设备树中使用interrupt-parent代表。代表中断产生设备的节点需要有interrupt-parent属性,该属性值指向一个phandle值,一般phandle的设备是一个中断控制器。如果一个中断产生设备没有interrupt-parent属性,它的interrupt-parent默认是父设备树。
每一个设备产生设备节点,都会有一个中断属性描述一个或多个中断源,每一个中断源是一个interrupt specifier(中断说明)。每一个中断说明是一个中断域说明,依赖根下的中断域节点,在中断域节点中包含interrupt-cells属性,是一个的值,代表一个中断说明。例如,一个开放的PCI中断控制器,一个中断说明有两个32-bit的值,组成中断号和leve/sense信息。
一个中断域是中断的上下文,在中断域中一个中断被解释执行。一个中断域是一个中断控制器或者一个中断连接。
下图展示设备树中父中断关系的图,同时展示了设备数及设备节点在逻辑中断树中的位置。
在例子中,展示信息如下:
2、常用中断属性简单说明
interrupts
Value-type:
描述:中断产生设备中的一个或多个中断描述。属性值包含多个中断说明的一个任意数字。中断说明的格式由绑定的中断域定义。
例如:一个开放的PIC中断域的中断说明包含两个数据单元,一个中断号和level/sense信息。如下值
interrupts = <0xA 8>;
interrupt-parent
值类型:
描述:由于中断树的层级和设备树层级不相同,因此该属性明确中断的父中断。如果一个中断设备中没有该属性,则默认父中断为父设备树。
interrupt-controller
值类型:
描述:定义一个设备节点是一个中断控制器
#interrupt-cells
值类型:
描述:定义一个中断域需要中断说明中由几个数据单元。
interrupt-map
值类型:
描述:(比较复杂,不做说明)
3、中断部分总结
中断产生设备使用属性:interrupts、interrupt-parent、interrupts-extended
中断控制器设备使用属性:#interrupt-cells、interrupt-controller
中断连接使用属性:#interrupt-cells、interrupt-map、interrupt-map-mask
1、基本设备节点
cpu、memory
2、根节点
根节点是/,需要由的属性如下:
3、节点别名
在根节点下使用aliases节点定义,别名名称有效字符如下:
例如:
aliases {
serial0 = "/simple-bus@fe000000/serial@llc500";
ethernet0 = "/simple-bus@fe000000/ethernet@31c000";
};
4、memory节点
不说明,有兴趣的自行看官方文档
5、chosen节点
该节点不代表真实设备,仅描述系统固件运行时需要的参数。必须是根节点的子节点。属性如下:
例如:
chosen {
bootargs = "root=/dev/nfs rw nfsroot=192.168.1.1 console=ttyS0,115200";
};
该节点比较重要,一般嵌入式开发,解决方案会单独把该节点拉出来成一个单独文件,在文件中描述更多参数,如内核log打印等级、分区信息等。
6.cpu节点
不说明,有兴趣的自行看官方文档。比较重要,建议详细了解
1、概述
当在设备树中添加一个设备节点时,对应的描述和属性和值被充分添加,这些属性和描述被传递到设备驱动中。
一些推荐练习如下:
3、4练习,在此处下面的内容中介绍
2、杂项属性
一些被多中类型设备使用的属性。
如:clock-frequency
其他属性不在此处详细说明。
DTB(Devicetree Blob)是平台二进制编码的设备树数据。被用来在软件程序间交换设备树数据。例如:当启动操作系统时,固件会传递DTB给kernel。
DTB设备树数据使用一个单一的、线性的、无指针的数据结构。包含一个小的头(header)、三个可变长度区域:内存预留块、结构数据块、字符串块。设备树作为一个整体,按照地址被加载进内存,像一个图表。
其余内容详见官网文档。
DTS是一个文本表示的文件,被dtc编译器编译为kernel中要使用二进制设备树。
其他的源码文件可以被DTS文件包含,被包含的源码文件后缀名应为”.dtsi“,被包含的文件也可以包含其他文件。
Labels
dts源码中支持一个标签和任何一个节点或者属性值关联。node中Phandle和路径引用可以使用标签代替明确指定,在编译时被自动集成进设备树。标签仅被使用在设备树源码中,不会在二进制设备树DTB中使用。
在标签名后面增加“:”,标签被创建;在标签名前加一个“&”,应用被创建。标签名可用字符,如下
节点使用标签
[label:] node-name[@unit-address] {
[properties definitions]
[child nodes]
};
如果节点中包含子节点,节点的属性在子节点前定义。
之前定义的节点可能被删除
/delete-node/ node-name;
/delete-node/ &label;
定义一个属性-值对
[label:] property-name = value;
如果属性值为empty
[label:] property-name;
之前已定义的属性可能被删除
/delete-property/ property-name;
属性值可能是一个32位整形数组、null终止的字符串、多字节字符串或这些形式的组合。
clock-frequency = <0x00000001 0x00000000>;
compatible = "simple-bus";
local-mac-address = [00 00 12 34 56 78];
或等价于
local-mac-address = [000012345678];
一个属性或许有多个值,值之间用‘,’隔开
compatible = "ns16550", "ns8250";
example = <0xf00f0000 19>, "a strange property format";
interrupt-parent = < &mpic >;
或者使用&node_full_path
interrupt-parent = < &{/soc/interrupt-controller@40000} >;
ethernet0 = &EMAC0;
reg = reglabel: <0 sizelabel: 0x1000000>;
prop = [ab cd ef byte4: 00 ff fe];
str = start: "string value" end: ;
文件布局
DTS完整布局如下
/dts-v1/;
[memory reservations]
/ {
[property definitions]
[child nodes]
};
/dts-v1/:dts文件标识,作为一个版本号。
预留内存定义一个二级制设备树预留内存表。dts源码中dts格式为:
/memreserve/ ;
其中地址和长度均是64为C风格整型。
DTS源文件编写格式算是有了一个清晰的框架,之际编写内容的,在使用中可以根据规范查找。DTS支持自定义扩展标记,因此可以结合驱动了解使用方式。