一、设备树
1、概述
DTSpec
指定了一个称为设备树的结构来描述系统硬件。引导程序将设备树加载到客户端程序的内存中,并将指向设备树的指针传递给客户端。
本章描述了设备树的逻辑结构,并指定了一组用于描述设备节点的基本属性。第 3 章指定了符合DTSpec
的设备树所需的某些设备节点。第 4 章描述了DTSpec
定义的设备绑定- 表示某些设备类型或设备类别的要求。第 5 章描述了设备树的内存编码。
设备树是一种树数据结构,其节点描述系统中的设备。每个节点都有描述所代表设备特性的属性/
值对。除了没有父节点的根节点之外,每个节点都只有一个父节点。
符合DTSpec
的设备树描述了系统中的设备信息,客户端程序不一定能动态检测到这些信息。例如,PCI
的体系结构使客户端能够探测和检测连接的设备,因此可能不需要描述PCI
设备的设备树节点。但是,如果无法通过探测检测到,则需要设备节点来描述系统中的PCI
主桥设备。
1、Example
图 2.1 显示了一个简单的设备树的示例表示,它几乎足以启动一个简单的操作系统,其中描述了平台类型、CPU
、内存和单个UART
。设备节点与每个节点内的属性和值一起显示。
2、设备树结构和约定
1、节点名称
节点名称要求
设备树中的每个节点都根据以下约定命名:
node-name@unit-address
node-name
组件指定节点的名称。它的长度应为1
到31
个字符,并且仅由来自表2.1
中字符集的字符组成。
节点名称应以小写或大写字符开头,并应描述设备的一般类别。
名称的单元地址部分特定于节点所在的总线类型。它由表 2.1 中字符集中的一个或多个ASCII
字符组成。
unit-address
必须与节点的reg
属性中指定的第一个地址相匹配。如果节点没有reg
属性,@unit-address
必须被省略,节点名称单独区分节点与树中同一级别的其他节点。特定总线的绑定可以为reg
格式和单元地址指定额外的、更具体的要求。
根节点没有节点名或单元地址。它由正斜杠 (/
) 标识。
名为cpu
的节点通过它们的单元地址值0
和1
来区分。名称为ethernet
的节点通过其单元地址值fe002000
和fe003000
来区分。
2、通用名称建议
节点的名称应该有点通用,反映设备的功能而不是其精确的编程模型。如果合适,名称应该是以下选项之一:
3、路径名称
设备树中的节点可以通过指定从根节点到所有后代节点到所需节点的完整路径来唯一标识。
指定设备路径的约定是:
/node-name-1/node-name-2/node-name-N
例如,在图 2.2 中,cpu #1 的设备路径为:
/cpus/cpu@1
根节点的路径是/
。
如果到节点的完整路径是明确的,则可以省略单元地址。
如果客户端程序遇到不明确的路径,则其行为未定义。
4、属性
设备树中的每个节点都有描述节点特征的属性。属性由名称和值组成。
1、属性名称
属性名称是表2.2
中显示的字符中的1
到31
个字符的字符串
非标准属性名称应指定唯一的字符串前缀,例如股票代码,以标识定义该属性的公司或组织的名称。例子:
fsl,channel-fifo-len ibm,ppc-interrupt-server#s linux,network-index
2、属性值
属性值是包含与该属性相关联的信息的零个或多个字节的数组。
如果传达真假信息,属性可能具有空值。在这种情况下,属性的存在或不存在是充分的描述。
表 2.3 描述了DTSpec
定义的一组基本值类型。
1、empty
值为空。当属性本身的存在或不存在具有足够的描述性时,用于传达真假信息。
2、u32
大端格式的32
位整数。
示例:32
位值0x11223344
在内存中表示为:
address 11 address+1 22 address+2 33 address+3 44
3、u64
表示大端格式的64
位整数。由两个值组成,其中第一个值包含整数的最高有效位,第二个值包含最低有效位。
示例:64
位值0x1122334455667788
将表示为两个单元格:<0x11223344 0x55667788>
。
该值将在内存中表示为:
address 11 address+1 22 address+2 33 address+3 44 address+4 55 address+5 66 address+6 77 address+7 88
4、string
字符串是可打印的并且以空值结尾。
示例:字符串“hello”
将在内存中表示为:
address 68 'h' address+1 65 'e' address+2 6C 'l' address+3 6C 'l' address+4 6F 'o' address+5 00 '\0'
5、prop-encoded-array
格式特定于属性。请参阅属性定义。
6、phandle
一个< u32 >值。phandle
值是一种引用设备树中另一个节点的方法。任何可以被引用的节点都定义了一个具有唯一< u32 >
值的phandle
属性。该数字用于具有phandle
值类型的属性值。
7、stringlist
连接在一起的< string >
值列表。
示例:字符串列表“hello”
、“world”
将在内存中表示为:
address 68 'h' address+1 65 'e' address+2 6C 'l' address+3 6C 'l' address+4 6F 'o' address+5 00 '\0' address+6 77 'w' address+7 6f 'o' address+8 72 'r' address+9 6C 'l' address+10 64 'd' address+11 00 '\0'
3、标准属性
DTSpec
为设备节点指定了一组标准属性。本节详细介绍了这些属性。DTSpec
定义的设备节点(见第3
章)可以指定有关标准属性使用的附加要求或约束。
第4
章描述了特定设备的表示,也可能规定了附加要求。
注意:本文档中的所有设备树节点示例都使用DTS
(设备树源)格式来指定节点和属性。
1、compatible(兼容)
1、属性名称
compatible
2、值类型
< stringlist >
3、描述
兼容属性值由一个或多个定义设备特定编程模型的字符串组成。客户端程序应使用此字符串列表来选择设备驱动程序。属性值由空终止字符串的串联列表组成,从最具体到最一般。它们允许设备表达其与一系列类似设备的兼容性,可能允许单个设备驱动程序匹配多个设备。
4、例子
compatible = "fsl,mpc8641", "ns16550";
在此示例中,操作系统将首先尝试定位支持fsl,mpc8641 的设备驱动程序。如果未找到驱动程序,它将尝试定位支持更通用的ns16550
设备类型的驱动程序。
2、model(模型)
1、属性名称
model
2、值类型
< string >
3、描述
模型属性值是一个string
,用于指定设备的制造商型号。
推荐的格式是:“manufacturer,model”
,其中manufacturer
是描述制造商名称的字符串(例如股票代码),model
指定型号。
4、例子
model = "fsl,MPC8349EMITX";
3、phandle()
1、属性名称
phandle
2、值类型
< u32 >
3、描述
phandle
属性指定一个在设备树中唯一的节点的数字标识符。phandle
属性值由需要引用与该属性关联的节点的其他节点使用。
4、例子
请参阅以下设备树摘录:
pic@10000000 { phandle = <1>; interrupt-controller;};
phandle
值定义为 1。另一个设备节点可以使用phandle
值为1
来引用pic
节点:
another-device-node { interrupt-parent = <1>;};
注意:可能会遇到旧版本的设备树,其中包含称为linux
,phandle
的此属性的弃用形式。为了兼容性,如果phandle
属性不存在,客户端程序可能希望支持linux
,phandle
。这两个属性的含义和用途是相同的。
注意:DTS
中的大多数设备树(参见附录 A)将不包含显式的phandle
属性。DTC
工具在将DTS
编译为二进制DTB
格式时会自动插入phandle
属性。
4、status(状态)
1、属性名称
status
2、值类型
< string >
3、描述
status
属性指示设备的操作状态。有效值在表2.4
中列出和定义。
1、okay
表示设备正在运行。
2、disabled
表示设备当前无法运行,但将来可能会运行(例如,某些设备未插入或关闭)。
有关禁用对给定设备的含义的详细信息,请参阅设备绑定。
3、reserved
表示设备可运行,但不应使用。通常用于由其他软件组件(如平台固件)控制的设备。
4、fail
表示设备未运行。在设备中检测到严重错误,如果不修复它不太可能投入使用。
5、fail-sss
表示设备未运行。在设备中检测到严重错误,如果不修理它不太可能投入使用。该值的 sss 部分特定于设备并指示检测到的错误条件。
5、#address-cells and #size-cells(地址单元和大小单元)
1、属性名称
#address-cells, #size-cells
2、值类型
< u32 >
3、描述
#address-cells
和#size-cells
属性可用于在设备树层次结构中具有子设备的任何设备节点,并描述子设备节点应如何寻址。
#address-cells
属性定义了用于对子节点的reg
属性中的地址字段进行编码的< u32 >
单元格的数量。
#size-cells
属性定义了用于对子节点的reg
属性中的大小字段进行编码的< u32 >
单元格的数量。
符合DTSpec
的引导程序应在所有具有子节点的节点上提供#address-cells
和#size-cells
。
如果丢失,客户端程序应假定#address-cells
的默认值为**2
,#size-cells
的值为1
**。
4、例子
请参阅以下设备树摘录:
soc {#address-cells = <1>; #size-cells = <1>;serial@4600 { compatible = "ns16550"; reg = <0x4600 0x100>; clock-frequency = <0>; interrupts = <0xA 0x8>; interrupt-parent = <&ipic>;}; };
在此示例中,soc
节点的**#address-cells
** 和**#size-cells
** 属性均设置为**1
。此设置指定需要一个单元格来表示地址**,并且需要一个单元格来表示节点的大小是这个节点的孩子。
串行设备reg
属性必须遵循在父节点中设置的此规范——地址由单个单元格(0x4600
) 表示,大小由单个单元格(0x100
) 表示。
6、reg()
1、属性名称
reg
2、属性值
< prop-encoded-array >
编码为任意数量的(地址,长度)对。
3、描述
reg 属性描述了设备资源在其父总线定义的地址空间内的地址。最常见的是,这意味着内存映射IO
寄存器块的偏移量和长度,但在某些总线类型上可能具有不同的含义。
该值是一个< prop-encoded-array >
,由任意数量的地址和长度对组成,< address length >
。
指定地址和长度所需的< u32 >
单元的数量是特定于总线的,并且由设备节点的父节点中的#address-cells
和#size-cells
属性指定。
如果父节点为#size-cells
指定值为**0
,则应省略reg
值中的长度字段**。
4、例子
假设片上系统中的设备有两个寄存器块,SOC
中偏移0x3000
处的32
字节块和偏移0xFE00
处的256
字节块。
reg
属性将编码如下(假设#address-cells
和#size-cells
值为1
):
reg = <0x3000 0x20 0xFE00 0x100>;
7、virtual-reg(虚拟-reg)
1、属性名称
virtual-reg
2、值类型
< u32 >
3、描述
virtual-reg
属性指定一个有效地址,该地址映射到设备节点的reg
属性中指定的第一个物理地址。此属性使引导程序能够为客户端程序提供已设置的虚拟到物理映射。
8、ranges(范围)
1、属性名称
ranges
2、值类型
< empty>
或< prop-encoded-array>
编码为任意数量的(子总线地址、父总线地址、长度)三元组。
3、描述
Ranges
属性提供了一种定义总线地址空间(子地址空间)和总线节点的父节点地址空间(父地址空间)之间的映射或转换的方法。
range
属性值的格式是任意数量的 (child-bus-address, parentbus-address, length
)
子总线地址是子总线地址空间内的物理地址。表示地址的单元格数量取决于总线,可以从该节点(出现range
属性的节点)的#address-cells
确定。父总线地址是父总线地址空间内的物理地址。表示父地址的单元数取决于总线,可以从定义父地址空间的节点的#address-cells
属性确定。长度指定子地址空间中范围的大小。表示大小的单元格数量可以从该节点(出现ranges
属性的节点)的#size-cells
确定。
如果属性定义为< empty>
值,则它指定父子地址空间相同,不需要地址转换。
如果该属性不存在于总线节点中,则假定节点的子节点与父地址空间之间不存在映射。
4、例子
地址转换示例:
soc {compatible = "simple-bus"; #address-cells = <1>; #size-cells = <1>; ranges = <0x0 0xe0000000 0x00100000>;serial@4600 { device_type = "serial"; compatible = "ns16550"; reg = <0x4600 0x100>; clock-frequency = <0>; interrupts = <0xA 0x8>; interrupt-parent = <&ipic>;}; };
soc
节点指定了一个range
属性
<0x0 0xe0000000 0x00100000>;
此属性值指定对于1024KB
范围的地址空间,在物理0x0
处寻址的子节点映射到物理0xe0000000
的父地址。
通过此映射,串行设备节点可以通过地址0xe0004600
处的加载或存储、0x4600
(在reg
中指定)的偏移量加上范围中指定的0xe0000000
映射来寻址。
9、dma-ranges
1、属性名称
dma-ranges
2、值类型
< empty>
或< prop-encoded-array>
编码为任意数量的(子总线地址、父总线地址、长度)三元组。
3、描述
dma-ranges
属性用于描述内存映射总线的直接内存访问(DMA
)结构,可以从源自总线的DMA
操作访问其设备树父级。它提供了一种定义总线物理地址空间和总线父级物理地址空间之间的映射或转换的方法。
dma-ranges
属性值的格式是(子总线地址、父总线地址、长度)的任意数量的三元组。指定的每个三元组描述了一个连续的DMA
地址范围。
子总线地址是子总线地址空间内的物理地址。表示地址的单元格数量取决于总线,可以从该节点(出现dma-ranges
属性的节点)的#address-cells
确定。父总线地址是父总线地址空间内的物理地址。表示父地址的单元数取决于总线,可以从定义父地址空间的节点的#address-cells
属性确定。长度指定子地址空间中范围的大小。表示大小的单元格数量可以从该节点(出现dma-ranges
属性的节点)的#size-cells
中确定。
4、例子
10、name (deprecated)
1、属性名称
name
2、值类型
< string >
3、描述
name
属性是一个字符串,指定节点的名称。此属性已弃用,不推荐使用。但是,它可能用于较旧的不符合DTSpec
的设备树。操作系统应该根据节点名称的节点名称组件来确定节点的名称(请参阅第2.2.1
节)。
11、device_type (deprecated)
1、属性名称
device_type
2、值类型
< string >
3、描述
IEEE 1275
中使用device_type
属性来描述设备的FCode
编程模型。由于DTSpec
没有FCode
,不推荐使用该属性的新用途,为了与IEEE 1275
派生的设备树兼容,它应该只包含在cpu
和内存节点上。
4、中断和中断映射
DTSpec
采用Open Firmware Recommendation Practice: Interrupt Mapping, Version 0.9 [b7]
中规定的表示中断的中断树模型。在设备树中存在一个逻辑中断树,它表示平台硬件中中断的层次结构和路由。虽然通常被称为中断树,但它在技术上更像是一个有向无环图。
中断源到中断控制器的物理连接在设备树中用interruptparent
属性表示。代表中断生成设备的节点包含一个中断父属性,该属性具有一个phandle
值,该值指向设备的中断路由到的设备,通常是一个中断控制器。如果中断生成设备没有中断父级属性,则假定其中断父级为其设备树父级。
每个中断生成设备都包含一个**interrupts
属性**,其中的值描述了该设备的一个或多个中断源。每个源都用称为中断说明符的信息表示。中断说明符的格式和含义是特定于中断域的,即它依赖于其中断域根节点上的属性。中断域的根使用#interrupt-cells
属性来定义对中断说明符进行编码所需的< u32>
值的数量。例如,对于Open PIC
中断控制器,中断说明符采用两个32
位值,由中断编号和中断的级别/检测信息组成。
中断域是解释中断说明符的上下文。域的根是中断控制器或中断关系。
1:中断控制器是:一个物理设备,需要一个驱动程序来处理通过它路由的中断。它也可以级联到另一个中断域。中断控制器由设备树中该节点上的中断控制器属性的存在来指定。
2:中断关系定义了一个中断域和另一个中断域之间的转换。转换基于特定于域和特定于总线的信息。域之间的这种转换是通过中断映射属性执行的。例如,PCI
控制器设备节点可以是一个中断关系,它定义了从PCI
中断命名空间(INTA、INTB
等)到具有中断请求 (IRQ
) 编号的中断控制器的转换。
当中断树的遍历到达没有中断属性的中断控制器节点时确定中断树的根,因此没有明确的中断父节点。
有关显示中断父关系的设备树的图形表示示例,请参见图2.3
。它显示了设备树的自然结构以及每个节点在逻辑中断树中的位置。
在图2.3
所示的例子中:
open-pic
中断控制器是中断树的根。中断树的根有三个子节点——将中断直接路由到open-pic
的设备device1
PCI host controller
GPIO Controller
存在三个中断域;一种根植于open-pic
节点,一种根植于PCI
主机桥节点,一种根植于GPIO
控制器节点。有两个连接节点;一个在PCI
主机桥上,一个在GPIO
控制器上。
1、中断生成设备的属性
1、interrupts
1、属性
interrupts
2、值类型
< prop-encoded-array >
编码为任意数量的中断说明符。
3、描述
设备节点的中断属性定义了设备产生的一个或多个中断。中断属性的值由任意数量的中断说明符组成。中断说明符的格式由中断域根的绑定定义。
中断被中断扩展属性覆盖,通常只应使用一个或另一个。
4、例子
开放PIC
兼容中断域中中断说明符的常见定义由两个单元组成;中断号和电平/检测信息。请参见以下示例,该示例定义了单个中断说明符,中断编号为0xA
,级别/检测编码为8
。
interrupts = <0xA 8>;
2、interrupt-parent
1、属性
interrupt-parent
2、值类型
< phandle >
3、描述
由于中断树中节点的层次结构可能与设备树不匹配,因此可以使用中断父级属性来明确定义中断父级。该值是中断父级的phandle
。如果设备缺少此属性,则假定其中断父级为其设备树父级。
3、interrupts-extended
1、属性
interrupts-extended
2、值类型
< phandle > < prop-encoded-array >
3、描述
interrupts-extended
属性列出了设备生成的中断。当设备连接到多个中断控制器时,应使用interrupts-extended
而不是interrupts
,因为它使用每个中断说明符对父phandle
进行编码。
4、例子
此示例显示了具有连接到两个独立中断控制器的两个中断输出的设备将如何使用中断扩展属性来描述连接。pic
是一个#interrupt-cells
说明符为2的中断控制器,而gic
是一个#interrupts-cells
说明符为1的中断控制器。
interrupts-extended = <&pic 0xA 8>, <&gic 0xda>;
中断和中断扩展属性是互斥的。设备节点应该使用一个或另一个,但不能同时使用两者。只有在需要与不理解中断扩展的软件兼容时才允许使用两者。如果两个中断扩展和存在中断,然后中断扩展优先。
2、中断控制器的属性
1、#interrupt-cells
1、属性
#interrupt-cells
2、值类型
< u32 >
3、描述
#interrupt-cells
属性定义为中断域编码中断说明符所需的单元数。
2、interrupt-controller
1、属性
interrupt-controller
2、值类型
< empty >
3、描述
中断控制器属性的存在将节点定义为中断控制器节点。
3、中断关系属性
一个中断关系节点应该有一个#interrupt-cells
属性。
1、interrupt-map
1、属性
interrupt-map
2、值类型
< prop-encoded-array >
编码为任意数量的中断映射条目。
3、描述
中断映射是连接节点上的一个属性,它将一个中断域与一组父中断域连接起来,并指定子域中的中断说明符如何映射到它们各自的父域。
中断映射是一张表,其中每一行都是一个映射条目,由五个部分组成:子单元地址、子中断说明符、中断父、父单元地址、父中断说明符。
child unit address
被映射的子节点的单元地址。指定这一点所需的32
位单元的数量由子节点所在总线节点的#address-cells
属性描述。
child interrupt specifier
被映射的子节点的中断说明符。指定此组件所需的 32 位单元数由此节点的 #interrupt-cells 属性描述 - 包含中断映射属性的连接节点。
interrupt-parent
指向子域映射到的中断父级的单个< phandle >
值。
parent unit address
中断父域中的单元地址。指定此地址所需的 32 位单元的数量由中断父字段指向的节点的#address-cells
属性描述。
parent interrupt specifier
父域中的中断说明符。指定此组件所需的 32 位单元的数量由中断父字段指向的节点的#interrupt-cells
属性描述。
通过将单元地址/中断说明符对与中断映射中的子组件进行匹配,在中断映射表上执行查找。由于单元中断说明符中的某些字段可能不相关,因此在完成查找之前应用掩码。这个掩码在interrupt-map-mask
属性中定义(见2.4.3.2 节)。
注意:子节点和中断父节点都需要定义#address-cells
和#interruptcells
属性。如果不需要单元地址组件,#address-cells
应明确定义为零。
2、interrupt-map-mask
1、属性
interrupt-map-mask
2、值类型
< prop-encoded-array >
编码为位掩码
3、描述
为中断树中的连接节点指定了中断映射掩码属性。此属性指定一个掩码,该掩码应用于在中断映射属性中指定的表中查找的传入单元中断说明符。
3、#interrupt-cells
1、属性
#interrupt-cells
2、值类型
< u32 >
3、描述
#interrupt-cells
属性定义为中断域编码中断说明符所需的单元数。
4、中断映射示例
下面显示了带有PCI
总线控制器的设备树片段的表示和用于描述两个PCI
插槽(IDSEL 0x11,0x12
)的中断路由的示例中断映射。插槽1
和2
的INTA
、INTB
、INTC
和INTD
引脚连接到Open PIC
中断控制器。
soc {compatible = "simple-bus"; #address-cells = <1>; #size-cells = <1>;open-pic {clock-frequency = <0>; interrupt-controller; /*中断控制器*/#address-cells = <0>; #interrupt-cells = <2>;}; pci {#interrupt-cells = <1>; #size-cells = <2>; #address-cells = <3>; interrupt-map-mask = <0xf800 0 0 7>; interrupt-map = < /* IDSEL 0x11 - PCI slot 1 */ 0x8800 0 0 1 &open-pic 2 1 /* INTA */ 0x8800 0 0 2 &open-pic 3 1 /* INTB */ 0x8800 0 0 3 &open-pic 4 1 /* INTC */ 0x8800 0 0 4 &open-pic 1 1 /* INTD */ /* IDSEL 0x12 - PCI slot 2 */ 0x9000 0 0 1 &open-pic 3 1 /* INTA */0x9000 0 0 2 &open-pic 4 1 /* INTB */ 0x9000 0 0 3 &open-pic 1 1 /* INTC */ 0x9000 0 0 4 &open-pic 2 1 /* INTD */>;}; };
一个Open PIC
中断控制器被表示并被标识为具有中断控制器属性的中断控制器。
中断映射表中的每一行由五部分组成:子单元地址和中断说明符,它们映射到具有指定父单元地址和中断说明符的中断父节点。
例如,中断映射表的第一行指定了插槽1
的INTA
的映射。该行的组件如下所示
子单元地址:0x8800 0 0
子中断说明符:1
中断父母:&open-pic
父母单位地址:(空,因为#address-cells = <0>
在open-pic
节点)父中断说明符:2 1
子单元地址为<0x8800 0 0>
。该值由三个32
位单元编码,由PCI
控制器的#address-cells
属性值(值为3
)决定。这三个单元代表PCI
地址,如PCI
总线的绑定所描述的。 编码包括总线号(0x0 << 16
)、设备号(0x11 << 11
) 和功能号(0x0 << 8
)。子中断说明符是<1>
,它指定了 PCI 绑定所描述的INTA
。这需要一个由PCI
控制器的#interrupt-cells
属性(值为1
)指定的32
位单元,它是子中断域。中断父级由指向插槽的中断父级的phandle
指定,即Open PIC
中断控制器。父节点没有单元地址,因为父中断域(open-pic
节点)的**#address-cells
值为<0>
**。父中断说明符是<2 1>
。表示中断说明符的单元格数(两个单元格)由中断父节点(open-pic
节点)上的#interrupt-cells
属性决定。值<2 1>
是由设备绑定为Open PIC
中断控制器指定的值(参见第4.5
节)。值<2>
指定INTA
连接到的中断控制器上的物理中断源编号。值<1>
指定级别/感知编码。
在此示例中,interrupt-map-mask
属性的值为<0xf800 0 0 7>
。在中断映射表中执行查找之前,此掩码应用于子单元中断说明符。
要查找IDSEL 0x12
(插槽2
)、功能0x3
的INTB
的open-pic
中断源编号,将执行以下步骤:
子单元地址和中断说明符形成值<0x9300 0 0 2>
。 地址的编码包括总线号(0x0 << 16
)、设备号(0x12 << 11
)和功能号(0x3 << 8
)。中断说明符是2
,这是根据PCI
绑定对INTB
的编码。 应用中断映射掩码值<0xf800 0 0 7>
,结果为<0x9000 0 0 2>
。在中断映射表中查找该结果,该表映射到父中断说明符<4 1>
。
4、Nexus 节点和说明符映射
1、Nexus 节点属性
一个连接节点应该有一个#<specifier>-cells
属性,其中<specifier>
是一些说明符空间,如‘gpio’
、‘clock’
、‘reset’
等。
1、#< specifier >-map
1、属性
#< specifier >-map
2、值类型
< prop-encoded-array >
编码为任意数量的说明符映射条目。
3、描述
< specifier >-map
是连接节点中的一个属性,它将一个说明符域与一组父说明符域连接起来,并描述子域中的说明符如何映射到它们各自的父域。
映射是一个表,其中每一行都是一个映射条目,由三个组件组成:子说明符、说明符父项和父说明符。
child specifier
被映射的子节点的说明符。指定此组件所需的 32 位单元数由此节点的#<specifier>-cells
属性描述 - 包含<specifier>-map
属性的连接节点。
specifier parent
一个<phandle>
值,指向子域被映射到的说明符父级。
parent specifier
父域中的说明符。指定此组件所需的 32 位单元数由说明符父节点的#-cells
属性描述。
通过将说明符与映射中的子说明符进行匹配,在映射表上执行查找。由于说明符中的某些字段可能不相关或需要修改,因此在完成查找之前应用掩码。该掩码在<specifier>-map-mask
属性中定义(参见第2.5.1.2
节)。
类似地,当映射说明符时,单元说明符中的某些字段可能需要保持不变并从子节点传递到父节点。在这种情况下,可以指定<specifier>-map-pass-thru
属性(参见第2.5.1.3
节)以将掩码应用于子说明符并复制与父单元说明符匹配的任何位。
2、< specifier >-map-mask
1、属性
< specifier >-map-mask
2、值类型
< prop-encoded-array >
编码为位掩码
3、描述
可以为连接节点指定< specifier >-map-mask
属性。此属性指定一个掩码,该掩码应用于在< specifier >-map
属性中指定的表中查找的子单元说明符。如果未指定此属性,则假定掩码是设置了所有位的掩码。
3、< specifier>-map-pass-thru
1、属性
< specifier>-map-pass-thru
2、值类型
< prop-encoded-array >
编码为位掩码
3、描述
可以为连接节点指定 -map-pass-thru 属性。此属性指定一个掩码,该掩码应用于在<specifier>-map
属性中指定的表中查找的子单元说明符。子单元说明符中的任何匹配位都被复制到父说明符。如果未指定此属性,则假定掩码是未设置位的掩码。
4、#< specifier>-cells
1、属性
#< specifier >-cells
2、值类型
< u32 >
3、描述
#< specifier >-cells
属性定义对域的说明符进行编码所需的单元格数。
2、说明符映射示例
下面显示了具有两个GPIO
控制器的设备树片段的表示和示例说明符映射,用于描述两个控制器上的几个gpios
通过板上的连接器到设备的GPIO
路由。扩展设备节点位于连接器节点的一侧,带有两个GPIO
控制器的SoC
位于连接器的另一侧。
soc {soc_gpio1: gpio-controller1 { #gpio-cells = <2>;};soc_gpio2: gpio-controller2 { #gpio-cells = <2>;}; };connector: connector { #gpio-cells = <2>; gpio-map = <0 0 &soc_gpio1 1 0>, <1 0 &soc_gpio2 4 0>, <2 0 &soc_gpio1 3 0>, <3 0 &soc_gpio2 2 0>;gpio-map-mask = <0xf 0x0>; gpio-map-pass-thru = <0x0 0x1>;};expansion_device { reset-gpios = <&connector 2 GPIO_ACTIVE_LOW>;};
gpio-map
表中的每一行都由三部分组成:一个子单元说明符,它被映射到一个带有父说明符的gpio-controller
节点。
例如,说明符映射表的第一行指定连接器的GPIO 0
的映射。该行的组件显示在此处
子说明符:0 0
说明符父:&soc_gpio1
父说明符:1 0
子说明符是<0 0>
,它在标志字段为0
的连接器中指定GPIO 0
。这需要由连接器节点的#gpio-cells
属性指定的两个32
位单元,这是子说明符域。
说明符父级由指向连接器的说明符父级的phandle
指定,即SoC
中的第一个GPIO
控制器。
父说明符是<1 0>
。表示gpio
说明符(两个单元格)的单元格数量由说明符父节点soc_gpio1
节点上的#gpio-cells
属性决定。
值<1 0>
是由设备绑定为GPIO
控制器指定的值。
值<1>
指定连接器上的GPIO 0
所连接到的GPIO
控制器上的GPIO
引脚编号。
值<0>
指定标志(低电平有效、高电平有效等)。
在本例中,gpio-map-mask
属性的值为<0xf 0>
。在gpio-map
表中执行查找之前,此掩码应用于子单元说明符。同样,gpio-map-pass-thru
属性的值为<0x0 0x1>
。在将子单元说明符映射到父单元说明符时,此掩码应用于子单元说明符。在此掩码中设置的任何位都将从父单元说明符中清除,并从子单元说明符复制到父单元说明符。
要从扩展设备的reset-gpios
属性查找GPIO 2
的连接器说明符源编号,将执行以下步骤:
子说明符形成值<2 GPIO_ACTIVE_LOW>
。 说明符使用每个GPIO
绑定的低电平有效标志对GPIO 2
进行编码。gpio-map-mask
值<0xf 0x0>
与子说明符进行AND
运算,结果为<0x2 0>
。结果在 gpio-map 表中查找,该表映射到父说明符<3 0>
和&soc_gpio1 phandle
。gpio-map-pass-thru
值<0x0 0x1>
被反转并与在gpio-map
表中找到的父说明符进行AND
运算,结果为<3 0>
。子说明符与gpio-map-pass-thru
掩码进行AND
运算,形成<0 GPIO_ACTIVE_LOW>
,然后与清除的父说明符<3 0>
进行OR
运算,得到<3 GPIO_ACTIVE_LOW>
。说明符<3 GPIO_ACTIVE_LOW>
附加到映射的phandle &soc_gpio1
导致<&soc_gpio1 3 GPIO_ACTIVE_LOW>
。
二、设备节点要求
1、基本设备节点类型
以下部分指定了符合DTSpec
的设备树中所需的基本设备节点集的要求。
所有设备树都应有一个根节点,并且以下节点应出现在所有设备树的根部:
一个/cpus
节点至少一个/memory
节点
2、Root 节点
设备树有一个根节点,所有其他设备节点都是其后代。根节点的完整路径是/
。
用法说明:
R = Required
(必须的)O = Optional
(可选的)OR = Optional but Recommended
(可选但推荐)SD = See Definition
(见定义)
注意:所有其他标准属性(第2.3
节)都是允许的,但都是可选的。
3、/aliases 节点
设备树可能有一个别名节点(/aliases),用于定义一个或多个别名属性。别名节点应位于设备树的根部并具有节点名称/aliases
。
/aliases
节点的每个属性都定义了一个别名。属性名称指定别名。属性值指定设备树中节点的完整路径。例如,属性serial0 = "/simple-bus@fe000000/ serial@llc500"
定义别名serial0
。
别名应是以下字符集中的1
到31
个字符的小写文本字符串。
别名值是一个设备路径并被编码为一个字符串。该值表示节点的完整路径,但该路径不需要引用叶节点。
客户端程序可以使用别名属性名称来引用完整的设备路径作为其字符串值的全部或部分。客户端程序在将字符串视为设备路径时,应检测并使用别名。
例如:
aliases { serial0 = "/simple-bus@fe000000/serial@llc500"; ethernet0 = "/simple-bus@fe000000/ethernet@31c000";};
给定别名serial0
,客户端程序可以查看/aliases
节点并确定别名指的是设备路径/simple-bus@fe000000/serial@llc500
。
4、/memory 节点
所有设备树都需要一个内存设备节点,它描述了系统的物理内存布局。如果系统有多个内存范围,可以创建多个内存节点,或者可以在单个内存节点的reg
属性中指定范围。
节点名称的单元名称组件(参见第2.2.1
节)应为内存。
客户端程序可以使用它选择的任何存储属性访问任何内存预留(参见第5.3
节)未涵盖的内存。但是,在更改用于访问真实页面的存储属性之前,客户端程序负责执行架构和实现所需的操作,可能包括从缓存中刷新真实页面。引导程序负责确保在不采取任何与存储属性更改相关的操作的情况下,客户端程序可以安全地访问所有内存(包括内存预留覆盖的内存),因为WIMG = 0b001x
。那是:
不需要直写不禁止缓存内存连贯性需要或不受保护或受保护
如果支持VLE
存储属性,则VLE=0
。
用法说明:
R = Required
(必须的)O = Optional
(可选的)OR = Optional but Recommended
(可选但推荐)SD = See Definition
(见定义)
注意:所有其他标准属性(第2.3
节)都是允许的,但都是可选的。
例子:
给定具有以下物理内存布局的64
位Power
系统:
RAM
:起始地址0x0
,长度0x80000000 (2 GB)
RAM
:起始地址0x100000000
,长度0x100000000 (4 GB)
内存节点可以定义如下,假设**#address-cells = <2>
** 和**#size-cells = <2>
**。
Example #1
memory@0 {device_type = "memory"; reg = <0x000000000 0x00000000 0x00000000 0x80000000 0x000000001 0x00000000 0x00000001 0x00000000>;};
Example #2
memory@0 {device_type = "memory"; reg = <0x000000000 0x00000000 0x00000000 0x80000000>;};memory@100000000 { device_type = "memory"; reg = <0x000000001 0x00000000 0x00000001 0x00000000>;};
reg
属性用于定义两个内存范围的地址和大小。跳过2 GB I/O
区域。请注意,根节点的**#address-cells
** 和**#size-cells
** 属性指定值为**2
,这意味着需要两个32 位单元来定义内存节点的reg
属性的地址和长度**。
5、/chosen 节点
/chosen
节点不代表系统中的真实设备,而是描述系统固件在运行时选择或指定的参数。它应该是根节点的子节点。
用法说明:
R = Required
(必须的)O = Optional
(可选的)OR = Optional but Recommended
(可选但推荐)SD = See Definition
(见定义)
注意:所有其他标准属性(第2.3
节)都是允许的,但都是可选的。
例子
chosen {bootargs = "root=/dev/nfs rw nfsroot=192.168.1.1 console=ttyS0,115200"; };
可能会遇到旧版本的设备树,其中包含称为linux
,stdout-path
的stdout-path
属性的弃用形式。为了兼容性,如果stdout-path
属性不存在,客户端程序可能希望支持linux
,stdout-path
。这两个属性的含义和用途是相同的。
6、/cpus 节点
所有设备树都需要一个/cpus
节点。它并不代表系统中的真实设备,而是充当代表系统CPU
的子CPU
节点的容器。
用法说明:
R = Required
(必须的)O = Optional
(可选的)OR = Optional but Recommended
(可选但推荐)SD = See Definition
(见定义)
注意:所有其他标准属性(第2.3
节)都是允许的,但都是可选的。
/cpus
节点可能包含跨cpu
节点通用的属性。有关详细信息,请参阅第3.7
节。
有关示例,请参阅第3.8.1
节。
7、/cpus/cpu* 节点
一个cpu
节点代表一个足够独立的硬件执行块,它能够运行操作系统而不会干扰可能运行其他操作系统的其他CPU
。
共享一个MMU
的硬件线程通常表示在一个cpu
节点下。如果设计了其他更复杂的CPU
拓扑,则CPU
的绑定必须描述拓扑(例如,不共享MMU
的线程)。
CPU
和线程通过统一的数字空间进行编号,该空间应尽可能匹配中断控制器的CPU
/线程编号。
跨cpu
节点具有相同值的属性可能会被放置在/cpus
节点中。客户端程序必须首先检查特定的cpu
节点,但如果未找到预期的属性,则应查看父/cpus
节点。这导致在所有CPU
上都相同的属性的更详细的表示。
每个CPU
节点的节点名称应为cpu
。
1、/cpus/cpu* 节点的一般属性
下表描述了cpu
节点的一般属性。表3.6
中描述的一些属性是具有特定适用细节的选择标准属性。
用法说明:
R = Required
(必须的)O = Optional
(可选的)OR = Optional but Recommended
(可选但推荐)SD = See Definition
(见定义)
注意:所有其他标准属性(第2.3
节)都是允许的,但都是可选的。
用法说明:
R = Required
(必须的)O = Optional
(可选的)OR = Optional but Recommended
(可选但推荐)SD = See Definition
(见定义)
注意:所有其他标准属性(第2.3
节)都是允许的,但都是可选的。
可能会遇到旧版本的设备树,它们在CPU
节点上包含总线频率属性。为了兼容性,客户端程序可能希望支持总线频率。该值的格式与clock-frequency
的格式相同。推荐的做法是使用时钟频率属性来表示总线节点上总线的频率。
2、TLB 属性
cpu
节点的以下属性描述了处理器MMU
中的转换后备缓冲区。
用法说明:
R = Required
(必须的)O = Optional
(可选的)OR = Optional but Recommended
(可选但推荐)SD = See Definition
(见定义)
注意:所有其他标准属性(第2.3
节)都是允许的,但都是可选的。
3、Internal (L1) Cache 属性
cpu
节点的以下属性描述了处理器的内部 (L1
) 缓存。
用法说明:
R = Required
(必须的)O = Optional
(可选的)OR = Optional but Recommended
(可选但推荐)SD = See Definition
(见定义)
注意:所有其他标准属性(第2.3
节)都是允许的,但都是可选的。
可能会遇到旧版本的设备树,其中包含称为l2-cache
的下一级缓存属性的弃用形式。为了兼容性,如果不存在next-level-cache
属性,客户端程序可能希望支持l2-cache
。这两个属性的含义和用途是相同的。
4、例子
这是一个带有一个子cpu
节点的/cpus
节点的示例:
cpus {#address-cells = <1>; #size-cells = <0>; cpu@0 {device_type = "cpu"; reg = <0>;d-cache-block-size = <32>; // L1 - 32 bytes i-cache-block-size = <32>; // L1 - 32 bytes d-cache-size = <0x8000>; // L1, 32K i-cache-size = <0x8000>; // L1, 32K timebase-frequency = <82500000>; // 82.5 MHz clock-frequency = <825000000>; // 825 MHz}; };
8、多级共享缓存节点(/cpus/cpu*/l?-cache)
处理器和系统可以实现附加级别的缓存层次结构。例如,二级 (L2
) 或三级 (L3
) 缓存。这些缓存可能与CPU
紧密集成,也可能在多个CPU
之间共享。
具有**“缓存”兼容值**的设备节点描述了这些类型的缓存。
缓存节点应定义一个phandle
属性,所有与缓存相关或共享缓存的cpu
节点或缓存节点都应包含一个下一级缓存属性,该属性指定缓存节点的phandle
。
缓存节点可以表示在CPU
节点下或设备树中的任何其他适当位置。
多级缓存和共享缓存用表3-9
中的属性表示。表3-8
中描述了L1
缓存属性。
用法说明:
R = Required
(必须的)O = Optional
(可选的)OR = Optional but Recommended
(可选但推荐)SD = See Definition
(见定义)
注意:所有其他标准属性(第2.3
节)都是允许的,但都是可选的。
1、例子
请参阅以下两个CPU
的设备树表示示例,每个CPU
都有自己的片上L2
和共享的L3
。
cpus {#address-cells = <1>; #size-cells = <0>;cpu@0 {device_type = "cpu"; reg = <0>; cache-unified; cache-size = <0x8000>; // L1, 32 KB cache-block-size = <32>; timebase-frequency = <82500000>; // 82.5 MHz next-level-cache = <&L2_0>; // phandle to L2L2_0:l2-cache { compatible = "cache"; cache-unified; cache-size = <0x40000>; // 256 KBcache-sets = <1024>; cache-block-size = <32>; cache-level = <2>; next-level-cache = <&L3>; // phandle to L3L3:l3-cache { compatible = "cache"; cache-unified; cache-size = <0x40000>; // 256 KB cache-sets = <0x400>; // 1024 cache-block-size = <32>; cache-level = <3>;}; }; };cpu@1 {device_type = "cpu"; reg = <1>; cache-unified; cache-block-size = <32>; cache-size = <0x8000>; // L1, 32 KB timebase-frequency = <82500000>; // 82.5 MHz clock-frequency = <825000000>; // 825 MHz cache-level = <2>; next-level-cache = <&L2_1>; // phandle to L2 L2_1:l2-cache { compatible = "cache"; cache-unified; cache-size = <0x40000>; // 256 KB cache-sets = <0x400>; // 1024 cache-line-size = <32>; // 32 bytes next-level-cache = <&L3>; // phandle to L3}; }; };
三、设备绑定
本章包含有关如何在设备树中表示特定类型和类别的设备的要求(称为绑定)。设备节点的compatible
属性描述了节点遵守的特定绑定(或多个绑定)。
绑定可以定义为彼此的扩展。例如,可以将新的总线类型定义为简单总线绑定的扩展。在这种情况下,compatible
属性将包含几个字符串来标识每个绑定——从最具体到最一般(参见第2.3.1
节,兼容)。
1、约束准则
1、一般原则
为设备创建新的设备树表示时,应创建一个绑定来完整描述设备所需的属性和值。这组属性应具有足够的描述性,以便为设备驱动程序提供所需的设备属性。
一些推荐的做法包括:
1、使用第2.3.1
节中描述的约定定义兼容字符串。
2、使用适用于新设备的标准属性(在第2.3
和2.4
节中定义)。这种用法通常至少包括reg
和interrupts
属性。
3、如果新设备适合DTSpec
定义的设备类,则使用第4
节(设备绑定)中指定的约定。
4、如果适用,请使用第4.1.2
节中指定的其他属性约定。
5、如果绑定需要新属性,则推荐的属性名称格式为:“<company>,<property-name>“
,其中<company>
是一个OUI
或唯一的短字符串,如标识绑定创建者的股票代码。
示例:“ibm,ppc-interrupt-server#s”
2、其他属性
本节定义了可能适用于多种类型的设备和设备类的有用属性列表。此处定义它们是为了促进名称和用法的标准化。
1、clock-frequency
2、reg-shift
3、label
2、串口设备
1、串行类绑定
串行设备类由各种类型的点对点串行线路设备组成。串行线路设备的示例包括8250 UART
、16550 UART
、HDLC
设备和BISYNC
设备。在大多数情况下,与RS-232
标准兼容的硬件适合串行设备类。
I2C
和SPI
(串行外设接口)设备不应表示为串行端口设备,因为它们有自己的特定表示。
1、clock-frequency
2、current-speed
2、美国国家半导体 16450/16550 兼容 UART 要求
与National Semiconductor 16450/16550 UART
(通用异步接收器发射器)兼容的串行设备应使用以下属性在设备树中表示。
用法说明:
R = Required
(必须的)O = Optional
(可选的)OR = Optional but Recommended
(可选但推荐)SD = See Definition
(见定义)
注意:所有其他标准属性(第 2.3 节)都是允许的,但都是可选的。
3、网络设备
网络设备是面向分组的通信设备。假定此类中的设备实现七层OSI
模型的数据链路层(第2
层)并使用媒体访问控制 (MAC
) 地址。网络设备的示例包括以太网、FDDI
、802.11
和令牌环。
1、网络类绑定
1、address-bits
2、local-mac-address
3、mac-address
4、max-frame-size
2、以太网特定注意事项
除了网络设备类指定的属性之外,还可以使用以下属性在设备树中表示基于IEEE 802.3 LAN
标准集合(统称为以太网)的网络设备。
本节中列出的属性扩充了网络设备类中列出的属性。
1、max-speed
2、phy-connection-type
phy-connection-type
属性的定义值:
3、phy-handle
4、电源 ISA 开放 PIC 中断控制器
本节规定了表示Open PIC
兼容中断控制器的要求。开放 PIC 中断控制器实现开放PIC
架构(由AMD
和Cyrix
联合开发)并在开放可编程中断控制器 (PIC
) 寄存器接口规范修订版1.2 [b18]
中指定。
Open PIC
中断域中的中断说明符用两个单元编码。第一个单元格定义中断号。第二个单元格定义了意义和级别信息。
感知和电平信息应在中断说明符中按如下方式编码:
0 = low to high edge sensitive type enabled 1 = active low level sensitive type enabled 2 = active high level sensitive type enabled 3 = high to low edge sensitive type enabled
用法说明:
R = Required
(必须的)O = Optional
(可选的)OR = Optional but Recommended
(可选但推荐)SD = See Definition
(见定义)
注意:所有其他标准属性(第2.3
节)都是允许的,但都是可选的。
5、simple-bus 兼容值
片上系统处理器可能具有无法探测设备的内部I/O
总线。无需额外配置即可直接访问总线上的设备。这种类型的总线被表示为具有“simple-bus”
兼容值的节点。
用法说明:
R = Required
(必须的)O = Optional
(可选的)OR = Optional but Recommended
(可选但推荐)SD = See Definition
(见定义)
四、扁平化设备树 (DTB) 格式
设备树Blob (DTB)
格式是设备树数据的平面二进制编码。它用于在软件程序之间交换设备树数据。例如,在启动操作系统时,固件会将DTB
传递给操作系统内核。
注意:IEEE1275
开放固件[IEEE1275]
没有定义DTB
格式。在大多数开放固件兼容平台上,通过调用固件方法遍历树结构来提取设备树。
DTB
格式在单个、线性、无指针数据结构中对设备树数据进行编码。它由一个小头部(见5.2
节)和三个可变大小的部分组成:内存保留块(见5.3
节)、结构块(见5.4
节)和字符串块(见5.5
节)。这些应该以该顺序出现在展平的设备树中。因此,设备树结构作为一个整体,当加载到内存地址时,将类似于图5.1
中的图(较低的地址在图的顶部)。
(自由空间)部分可能不存在,但在某些情况下,它们可能需要满足各个块的对齐约束(参见第5.6
节)。
1、版本控制
自从格式的原始定义以来,已经定义了几个版本的扁平设备树结构。标头中的字段给出版本,以便客户端程序可以确定设备树是否以兼容格式编码。
本文档仅描述了该格式的第17
版。DTSpec
兼容的引导程序应提供版本17
或更高版本的设备树,并应提供与版本16
向后兼容的版本的设备树。DTSpec
兼容的客户端程序应接受向后兼容版本17
的任何版本的设备树,并且可以接受其他版本以及。
注意:版本是关于设备树的二进制结构,而不是它的内容。
2、Header
devicetree
的头布局由以下C
结构定义。所有的头字段都是32
位整数,以大端格式存储。
struct fdt_header { uint32_t magic; uint32_t totalsize; uint32_t off_dt_struct; uint32_t off_dt_strings; uint32_t off_mem_rsvmap; uint32_t version; uint32_t last_comp_version; uint32_t boot_cpuid_phys; uint32_t size_dt_strings; uint32_t size_dt_struct;};
3、内存保留块
1、目的
内存保留块为客户端程序提供物理内存中保留的区域列表;也就是说,不应将其用于一般内存分配。它用于保护重要数据结构不被客户端程序覆盖。例如,在一些带有IOMMU
的系统上,由DTSpec
引导程序初始化的TCE
(翻译控制条目)表需要以这种方式进行保护。同样,在客户端程序运行时使用的任何引导程序代码或数据都需要保留(例如,开放固件平台上的RTAS
)。DTSpec
不要求引导程序提供任何此类运行时组件,但它不禁止实现作为扩展这样做。
更具体地说,客户端程序不应访问保留区域中的内存,除非引导程序提供的其他信息明确指示它应该这样做。客户端程序然后可以以指示的方式访问保留存储器的指示部分。引导程序可以向客户端程序指示保留内存的特定用途的方法可能出现在本文档、它的可选扩展或特定于平台的文档中。
引导程序提供的保留区域可以但不要求包含设备树blob
本身。客户端程序应确保在使用之前不会覆盖此数据结构,无论它是否在保留区域中。
任何在内存节点中声明并被引导程序访问或在客户端进入后被引导程序访问的内存都必须保留。此类访问的示例包括(例如,通过不受保护的虚拟页面进行推测性内存读取)。
这个要求是必要的,因为任何未被保留的内存都可以被具有任意存储属性的客户端程序访问。
任何由引导程序或由引导程序引起的对保留内存的访问都必须在不禁止缓存和内存一致性要求(即WIMG = 0bx01x
)的情况下完成,另外对于第三册-S 实现,不要求直写(即,WIMG = 0b001x
) 。此外,如果支持 VLE 存储属性,则必须在VLE=0
时完成对保留内存的所有访问。
此要求是必要的,因为客户端程序被允许映射具有指定为不要求直写、不禁止缓存和要求内存一致性(即,WIMG = 0b001x
)和VLE = 0
的存储属性的内存。客户端程序可能会使用包含保留内存的大型虚拟页面。但是,客户端程序可能不会修改保留内存,因此引导程序可能会按照需要直写的方式执行对保留内存的访问,其中此存储属性的冲突值在体系结构上是允许的。
2、Format
内存预留块由一组64
位大端整数对的列表组成,每对由以下C
结构表示。
struct fdt_reserve_entry { uint64_t address; uint64_t size;};
每对都给出了保留内存区域的物理地址和大小(以字节为单位)。这些给定区域不应相互重叠。保留块列表应以地址和大小都等于0
的条目结束。注意地址和大小值始终为64
位。在32
位CPU
上,值的高32
位被忽略。
内存预留块中的每个uint64_t
以及整个内存预留块都应位于距设备树blob
开头的8
字节对齐偏移处(参见第 5.6 节)。
4、结构块
结构块描述了设备树本身的结构和内容。它由带有数据的令牌序列组成,如下所述。这些被组织成线性树结构,如下所述。
结构块中的每个标记,以及结构块本身,都应位于距设备树blob
开头的4
字节对齐偏移处(见 5.6)。
1、词汇结构
结构块由一系列片段组成,每个片段以一个标记开头,即一个大端32
位整数。一些令牌后跟额外的数据,其格式由令牌值决定。所有令牌都应在32
位边界上对齐,这可能需要在前一个令牌数据之后插入填充字节(值为0x0
)。
五种令牌类型如下:
1、FDT_BEGIN_NODE (0x00000001)
FDT_BEGIN_NODE
标记标志着节点表示的开始。后面应该跟节点的单元名称作为额外数据。名称存储为以空字符结尾的字符串,并且应包括单元地址(参见第2.2.1
节),如果有的话。节点名称后跟零填充字节(如果需要对齐),然后是下一个标记,可以是除FDT_END
之外的任何标记。
2、FDT_END_NODE (0x00000002)
FDT_END_NODE
标记标志着节点表示的结束。这个令牌没有额外的数据;所以紧随其后的是下一个标记,它可以是除FDT_PROP
之外的任何标记。
3、FDT_PROP (0x00000003)
FDT_PROP
标记标志着设备树中一个属性表示的开始。其后应是描述该属性的额外数据。该数据首先由属性的长度和名称组成,表示为以下C
结构:
struct {uint32_t len; uint32_t nameoff;}
此结构中的两个字段都是32
位大端整数。
len
以字节为单位给出属性值的长度(可能为零,表示一个空属性,请参阅第2.2.4.2
节)。nameoff
给出了字符串块(参见第5.5
节)的偏移量,在该块中属性的名称存储为以空字符结尾的字符串。
在此结构之后,属性的值作为长度为len
的字节字符串给出。该值后跟零填充字节(如有必要)以与下一个32
位边界对齐,然后是下一个令牌,它可以是除FDT_END
之外的任何令牌。
4、FDT_NOP (0x00000004)
FDT_NOP
令牌将被任何解析设备树的程序忽略。这个令牌没有额外的数据;因此紧随其后的是下一个令牌,它可以是任何有效的令牌。树中的属性或节点定义可以用FDT_NOP
令牌覆盖以将其从树中删除,而无需移动设备树 blob 中树表示的其他部分。
5、FDT_END (0x00000009)
FDT_END
标记标记结构块的结束。应该只有一个FDT_END
标记,它应该是结构块中的最后一个标记。它没有额外的数据;所以紧跟在FDT_END
标记之后的字节从结构块的开头偏移等于设备树blob
标头中size_dt_struct
字段的值。
2、树状结构
devicetree
结构表示为线性树:每个节点的表示以FDT_BEGIN_NODE
标记开始,以FDT_END_NODE
标记结束。节点的属性和子节点(如果有)在FDT_END_NODE
之前表示,因此这些子节点的FDT_BEGIN_NODE
和FDT_END_NODE
令牌嵌套在父节点的令牌中。
整个结构块由根节点的表示(其中包含所有其他节点的表示)组成,后跟FDT_END
标记以标记整个结构块的结尾。
更准确地说,每个节点的表示由以下组件组成:
(可选)任意数量的FDT_NOP
令牌FDT_BEGIN_NODE
令牌 节点的名称作为以空字符结尾的字符串[将填充字节归零以对齐4
字节边界] 对于节点的每个属性: (可选)任意数量的FDT_NOP
令牌FDT_PROP
令牌 第5.4.1
节中给出的属性信息[将填充字节归零以对齐4
字节边界] 这种格式的所有子节点的表示(可选)任意数量的FDT_NOP
令牌FDT_END_NODE
令牌
请注意,此过程要求特定节点的所有属性定义在该节点的任何子节点定义之前。虽然如果属性和子节点混合在一起,结构不会有歧义,但是处理扁平树所需的代码被这个要求简化了。
5、字符串块
strings
块包含表示树中使用的所有属性名称的字符串。这些空终止的字符串在本节中简单地连接在一起,并从结构块中通过偏移量引用到字符串块中。
字符串块没有对齐约束,可以出现在距设备树blob
开头的任何偏移处。
6、对齐
对于在没有未对齐内存访问的情况下使用的内存预留和结构块中的数据,它们应位于适当对齐的内存地址。具体而言,内存预留块应与8
字节边界对齐,结构块应与4
字节边界对齐。
此外,可以在不破坏子块对齐的情况下重新定位整个设备树blob
。
如前几节所述,结构块和字符串块应与设备树blob
的开头对齐偏移。为了确保块在内存中的对齐,确保设备树作为一个整体被加载到与任何子块的最大对齐对齐的地址处,即8
字节边界就足够了。符合DTSpec
的引导程序应在这样的对齐地址加载设备树blob
,然后再将其传递给客户端程序。如果DTSpec
客户端程序将设备树blob
重新定位到内存中,它应该只将其重新定位到另一个8
字节对齐的地址。
五、设备树源 (DTS) 格式(版本 1)
Devicetree Source (DTS)
格式是一种形式的设备树的文本表示,dtc
可以将其处理为内核期望的形式的二进制设备树。下面的描述不是DTS
的正式语法定义,而是描述了用于表示设备树的基本结构。
1、编译器指令
可以从DTS
文件中包含其他源文件。包含文件的名称应以“.dtsi”
结尾。包含的文件又可以包含其他文件。
/include/ "FILE"
2、Labels
源格式允许将标签附加到设备树中的任何节点或属性值。Phandle
和路径引用可以通过引用标签自动生成,而不是显式指定 phandle 值或节点的完整路径。标签仅用于设备树源格式,不会编码到DTB
二进制文件中。
标签长度为1~31
个字符,只能由表6.1
中的字符组成,且不能以数字开头。
标签是通过在标签名称后附加一个冒号(‘:’)
来创建的。引用是通过在标签名称前加上与号(‘&’)
来创建的。
3、节点和属性定义
Devicetree
节点使用节点名称和单元地址进行定义,大括号标记节点定义的开始和结束。它们前面可能有一个标签。
[label:] node-name[@unit-address] { [properties definitions] [child nodes]};
节点可能包含属性定义和/或子节点定义。如果两者都存在,则属性应位于子节点之前。
之前定义的节点可能会被删除。
/delete-node/ node-name; /delete-node/ &label;
属性定义是以下形式的名称值对:
[label:] property-name = value;
除了具有以下形式的空(零长度)值的属性:
[label:] property-name;
之前定义的属性可能会被删除。
/delete-property/ property-name;
属性值可以定义为32
位整数单元的数组、以null
结尾的字符串、字节串或这些的组合。
单元格数组由围绕空格分隔的 C 样式整数列表的尖括号表示。例子:
interrupts = <17 0xc>;
值可以表示为括号内的算术、按位或逻辑表达式。
Arithmetic operators+ add - subtract * multiply / divide % modulo
Bitwise operators& and | or ^ exclusive or ~ not << left shift >> right shift
Logical operators&& and || or ! not
Relational operators< less than > greater than <= less than or equal >= greater than or equal == equal != not equal
Ternary operators ?: (condition ? value_if_true : value_if_false)
一个64
位值用两个32
位单元表示。例子:
clock-frequency = <0x00000001 0x00000000>;
以空字符结尾的字符串值使用双引号表示(属性值被视为包含终止NULL
字符)。例子:
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";
在元胞数组中,对另一个节点的引用将扩展到该节点的phandle
。引用可以是&
后跟节点的标签。例子:
interrupt-parent = < &mpic >;
或者它们可能是&
后跟花括号中的节点的完整路径。例子:
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: ;
4、文件布局
版本1 DTS
文件具有整体布局:
/dts-v1/; [memory reservations] / {[property definitions] [child nodes]};
/dts-v1/
;
应存在以将文件标识为版本1 DTS
(没有此标记的dts
文件将被dtc
视为处于过时的版本0
中,除了其他小的但不兼容的更改之外,它使用不同的整数格式)。
内存预留为devicetree blob
的内存预留表定义了一个条目。它们具有以下形式:/memreserve/ < address> < length>;
其中
< address>
和< length>
是64
位C
风格的整数。
这/ { };
部分定义了设备树的根节点。支持C
风格(/* . . . */)
和C++
风格(//)
注释。