内核被传递第一个指向一个内存区域的物理地址,它以一个头开始,定义在linux/of_fdt.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | struct boot_param_header { u32 magic; /* magic word OF_DT_HEADER */ u32 totalsize; /* total size of DT block */ u32 off_dt_struct; /* offset to structure */ u32 off_dt_strings; /* offset to strings */ u32 off_mem_rsvmap; /* offset to memory reserve map */ u32 version; /* format version */ u32 last_comp_version; /* last compatible version */ /* version 2 fields below */ u32 boot_cpuid_phys; /* Which physical CPU id we're booting on */ /* version 3 fields below */ u32 size_dt_strings; /* size of the strings block */ /* version 17 fields below */ u32 size_dt_struct; /* size of the DT structure block */ }; |
有下列常量:
1 2 3 4 5 6 7 8 | /* Definitions used by the flattened device tree */ #define OF_DT_HEADER 0xd00dfeed /* 4: version, 4: total size */ #define OF_DT_BEGIN_NODE 0x1 /* Start node: full name */ #define OF_DT_END_NODE 0x2 /* End node */ #define OF_DT_PROP 0x3 /* Property: name off, size, content */ #define OF_DT_END 0x9 |
magic,是一个常量:OF_DT_HEADER
totalsize,是整个DT block的大小,包括头。
off_dt_struct,是设备树结构体的开始。
off_dt_strings,是设备树字符串部分的开始。
off_mem_rsvmap,保留内存区的开始,是一个内存区的list,每个内存区有2个64位整数,表示物理地址和大小,内核不应使用这些内存。
整个DT block的layout如下:
Device tree generalities
unit name由node name @ unit address 组成。
内核实际上不使用unit address,unit address只是用来保证node unit name唯一,在给定的tree level上。
没有地址且不可能有相同名字的节点可省略unit address,比如/memory,/cpus。
每个可以被其它节点引用的节点,需要有一个phandle或者linux,phandle属性。
Device tree "structure" block
是一个线性树结构。单个节点的基本结构如下:
* token OF_DT_BEGIN_NODE (that is 0x00000001)
* for version 1 to 3, this is the node full path as a zero
terminated string, starting with "/". For version 16 and later,
this is the node unit name only (or an empty string for the
root node)
* [align gap to next 4 bytes boundary]
* for each property:
* token OF_DT_PROP (that is 0x00000003)
* 32-bit value of property value size in bytes (or 0 if no
value)
* 32-bit value of offset in string block of property name
* property value data if any
* [align gap to next 4 bytes boundary]
* [child nodes if any]
* token OF_DT_END_NODE (that is 0x00000002)
Device tree "strings" block
为了节省空间,属性名存储在这个块。
device的address格式是由parent bus类型决定的,由parent node的#address-cells和#size-cells属性决定。这两个属性不会由子节点继承。
root节点有这些属性,来定义直接映射到处理器bus的设备的地址格式。
每个cell是32位数,两个cell就是64位,cell被拼接,以big endian格式。
reg属性是 a tuple of "address size"
如果一个bus支持各种地址空间和其他的flags。这些flags是放到物理地址的前面,如PCI有3个cells。top cell包含flags device numbers等。
有的地址是动态分配的。
如果你的bus地址很复杂,你可以在prom_parse.c中添加。
reg只定义addresses和sizes,为了向上翻译地址,如翻译成parent bus addresses。所有的bus必须包含ranges属性。如果没有ranges属性,翻译被认为是不可能的。ranges属性是一个list of:
bus address, parent bus address, size
如果ranges属性是空的,则认为parent bus address和子bus address相同。
cpu 节点需要device_type = cpu
memory节点需要device_type=memory
/chosen节点是一个特殊的节点,它不是一个设备或bus,用来存储环境变量。
/soc<socname> 节点,表明是一个SoC,如/soc8540。
https://www.devicetree.org/open-firmware/practice/imap/imap0_9d.pdf
上述文档详细阐述了interrupt tree。
每个产生中断的设备,有一个interrupt属性,值是中断的ID,有中断域的#interrupt-cells决定,值的格式。
interrupt-parent 是 interrupt tree parent node的phandle值。
#interrupt-cells通常为2,第一个是中断号,第二个是触发方式,高低电平,上升沿,下降沿等。
Specifying dma bus information
略