- The DT block format
This chapter defines the format of the FDT (flattened device tree) passed to the kernel. The properties it contains and the attributes required by the kernel are described in subsequent chapters.
Note: The DT block should be loaded into the main memory, the kernel needs to be able to access the DT block in both real mode and protected mode, so the first address of DT block cannot be remapped. The Boot loader is responsible for loading the DT block into memory and then passing its first address to the kernel.
1.1 Header
When the Boot loader passes the device tree to the kernel, it is actually the physical address of the DT in memory, and the beginning part is the DT header information, which is the struct in the Inlude/linux/of_fdt.h boot_param_ Header Structure Description:
318struct Boot_param_header {
319 U32 Magic; /* Magic word Of_dt_header */
U32 totalsize; /* Total size of DT block */
321 U32 off_dt_struct; /* Offset to structure */
322 U32 off_dt_strings; /* Offset to strings */
323 u32 Off_mem_rsvmap; /* Offset to memory reserve map
324 */
325 u32 version; /* Format version */
326 u32 last_comp_version; /* Last compatible version */
327
328/* Version 2 fields below */
329 U32 Boot_cpuid_phys; /* Which physical CPU ID we ' re
Booting on */
331/* Version 3 fields below */
332 U32 size_dt_strings; /* Size of the strings block */
333
334/* Version below fields */
335 u32 size_dt_struct; /* Size of the DT structure block */
336};
At the same time, some constants are defined to describe the header information, including:
341#define of_dt_header 0xd00dfeed/* 4:version,
342 4:total Size */
343#define of_dt_begin_node 0x1/* Start node:full Name
344 */
345#define of_dt_end_node 0x2/* END NODE */
346#define of_dt_prop 0x3/* property:name off,
347 size, Content */
348#define Of_dt_end 0x9
The values in all headers are stored on disk in the big-endian mode, and the following sections detail the meanings of the attributes in the header. It is important to note that all offset values are offset (in bytes) from the header, which is the physical address of the DT block.
The Magic attribute identifies the beginning of the DT block header, whose value is 0xd00dfeed, which is the value represented by the macro definition Of_dt_header.
The totalsize represents the size of all DT blocks containing the DT header, and the DT block contains all the data structures, such as the device tree structure, the string set, the memory reserve, and so on.
The off_dt_struct represents the offset address from the DT header to the structure zone in the DT block. The off_dt_strings represents the offset address from the DT header to the strings zone in the DT block.
The off_mem_rsvmap represents the offset address from the DT header to the reserved memory map area. A memory-reserved block graph is a set of 64-bit integer pairs, each of which contains a physical address and size, and the last node of the list that constitutes the data is a pair of integers with a size of 0. The memory reserve block graph is used to tell the kernel not to occupy the memory area during memory allocation, especially during the early initialization of the kernel. This allows us to store information similar to the DT Block,ramdisk, which we do not want to be overwritten by other kernel modules, for subsequent use by the kernel.
Version indicates the revision number of the DT. Version 1 is deactivated, version 2 adds the Boot_cpuid_phys zone, and version 3 increases the size of the strings chunk and allows the kernel to reposition it. Version 17 is currently in use and it adds the Size_dt_struct field.
Last_comp_version represents the minimum forward compatible version.
The Boot_cpuid_phys field appears only in version 2, indicating the physical CPU ID. If you are using a multiprocessor system, this field should match the Reg attribute of the CPU node.
The Size_dt_strings field appears in version 3 and later, representing the size of the strings chunk.
The Size_dt_struct field appears in version 17 and later, representing the size of the structure chunk.
Therefore, the typical DT block layout diagram should be as follows:
Among them, the alignment gap region does not have to exist, whether they exist and size independent of the alignment requirements of each data block.
1.2 Device Tree generalities
The device tree itself is differentiated into two blocks of structure and strings, each of which is aligned in 4-byte chunks. The layout of the device tree follows the IEEE 1275 device tree specification. Essentially, it is a tree structure with many nodes, each with two or more well-known properties, each with a value or no value. In addition, because it is a tree structure, each node except the root node has and has only one parent node, and the root node does not have a parent node.
A node has two names, and the true node name is typically described by a property of the node's name type, which must be specified between version 1 and version 3. Starting with version 16, this property becomes optional, but if it is not explicitly specified, the property is specified using the unit name during compilation.
The Unit name is used to differentiate between nodes that use the same name at the same level, and its usual form is [email protected]_address,unit address usually refers to the device on the mounted bus. Unit name does not exist in the form of one of its own properties, but rather as part of the DT structure. It is typically used to represent the path of the device node in dt. Kernel generic code typically does not use unit address (although some board-level support code is used), so the only requirement for the unit address here is to ensure that unit name is unique at the same level. Nodes that do not have any address concepts, as well as some nodes that do not have adjacent nodes (such as/CPU or/memory), usually omit the unit address, or use @0 to represent it. The unit name is used to define the full path of the node, and the complete path is a concatenation of all parent nodes starting from the root node, separated by A/sign, which is somewhat similar to the path in the Linux file system. The root node has no unit name and no unit address, and its path is "/".
Each node represents a device that is actually present. Each node can be referenced by properties of other nodes, but this requires that we define a property of type "Phandle" or "Linux,phandle" for the referenced node. The "Phandle" property is a 32-bit numeric value that uniquely identifies a node, and the only requirement is that the values of all the Phandle properties in DT cannot be duplicated.
Now let's look at a simple example:
564/o Device-tree
565 |-name = "Device-tree"
566 |-model = "Myboardname"
567 |-compatible = "Myboardfamilyname"
568 |-#address-cells = <2>
569 |-#size-cells = <2>
570 |-Linux,phandle = <0>
571 |
572 o CPUs
573 | | -Name = "CPUs"
574 | | -Linux,phandle = <1>
575 | | -#address-cells = <1>
576 | | -#size-cells = <0>
577 | |
578 | o Powerpc,[email protected]
579 | |-name = "powerpc,970"
580 | |-Device_type = "CPU"
581 | |-reg = <0>
582 | |-clock-frequency = <0x5f5e1000>
583 | |-64-bit
584 | |-Linux,phandle = <2>
585 |
586 o [Email protected]
587 | |-name = "Memory"
588 | |-device_type = "Memory"
589 | |-reg = <0x00000000 0x00000000 0x00000000 0x20000000>
590 | |-Linux,phandle = <3>
591 |
592 o Chosen
593 |-name = "Chosen"
594 |-Bootargs = "Root=/dev/sda2"
595 |-Linux,phandle = <4>
Where double quotation marks contain a string representing the Terminator as ' 0 ', and the brackets contain the represented value, and if the hexadecimal value begins with 0x.
1.3 Device Tree "structure" block
The structure block in DT is a linear tree-shaped structure. It uses "Of_dt_begin_node" to mark the beginning of a node, and "Of_dt_end_node" marks the end of a node. Child nodes are defined before the of_dt_end_node of the parent node. Of_dt_being_node,of_dt_end_node,of_dt_end and other tokens are 32-bit values. The of_dt_end tag appears at the end of the structure chunk.
The contents of a node can be summarized as the start tag, the full path, the attribute list, the sub-node list, and the end tag. The structure of each sub-node is similar to the one described above. The place to note is that the list of attributes is best placed before the list of child nodes.
1.4 Device Tree "strings" block
Because property names are usually lengthy strings, to save space, DT stores them separately in the strings block, which is a string of all attribute names (The Terminator is ' 0 ') concatenated together, The attribute defined in the structure chunk contains the offset address of the property name string (the offset address from the beginning of the strings chunk).
- Required content of the device tree
2.1 Note about cells and address representation
Typically, the format of the device address is defined by the parent bus type based on the #address-cells and #size-cells properties. It is important to note that the child nodes do not inherit the #address-cells and #size-cells properties of the parent node, so the child nodes that have child nodes must specify both property values themselves. The kernel requires the root node to define the device address format for devices that map directly to the processor bus, and also by specifying both attribute values.
A cell represents a 32-bit value, #address-cells represents the bit length of the device address, #size-cells represents the bit length of the device size. If both attribute values are 2, they are made up of two 64-bit numeric values (big-endian mode).
The "Reg" property is usually a tuple in the form of "address size", where the data length of address and size is determined by the two attribute values. These flags are usually added to the highest number of physical addresses when the bus supports different address spaces and flags that correspond to the address space. For example, the physical address of a PCI bus consists of three cells, and the bottom two veneer includes a real physical address, and a unit at the top includes an address space identifier, a flag bit, a bus number, and a device number.
For buses that support the dynamic allocation of device addresses, the device address is typically not specified through the Reg attribute, but first indicates that the device address is dynamically allocated through a flag. Next, provide a separate "assigned-addresses" property to specify the assigned device address. This can be referred to as PCI bindings.
Typically, a bus that does not have an address space and dynamic address allocation mechanism is what the kernel wants to see because the kernel does not need to define a separate address translation function for Bus_type.
The "Reg" property is simply the size of the device address and Device Register group defined in a given bus. In order to convert the device address to a higher bus address (into the bus address space) or to a higher level of CPU physical address space, all buses must contain a "ranges" attribute. If the ranges property is not specified, then it is assumed that there is no address translation mechanism. For example, a device's register group is not visible to the bus. The ranges properties of the bus are in the following format:
Bus address, parent bus address, size
The format of "bus address" is determined when the bus node is defined, and for a PCI bridge device, it is the PCI address space address. Therefore, (bus address, size) defines the address families of a set of sub-devices. The format of the "Parent bus address" is defined by the parent bus node of the bus node. For example, for a PCI host controller, it is the physical address space address of the CPU, and for a Pci-isa bridge device, it is a PCI address space address. The "Parent bus address" defines the base addresses that the device address families map in the parent bus address space.
The "ranges" property can also be empty, indicating that the device register group is visible to the parent bus, but uses a consistent mapping mechanism. In other words, it is the same as the parent bus address space and the child bus address space.
2.2 Note about "compatible" propertites
This property is optional, but it is strongly recommended to add this attribute to the device node and root node. The format of the "compatible" property is a set of strings concatenated with ' 0 ' as the Terminator. They represent devices that are compatible with a series of similar devices, and in some cases can have a driver match multiple devices, regardless of their real name.
2.3 Note about "name" Propertites
Early adopters populate the "name" property with a different real name, but it is now universally accepted and respected to populate the "name" property with a name similar to the device class (usually Device_type). For example, the NIC controller is named "Ethernet", then an additional "model" attribute is used to define the exact chip class/model, and the "compatible" attribute is used to define a compatible class of devices, which allows a driver to support a variety of similar devices. At the same time, the kernel usually does not strictly restrict the value of the "name" attribute, which is gradually becoming a canonical operation.
Also, in version 16, set the Name property to an optional property. If the Name property is not specified, the unit name is refactored to the Name property, which means that the portion of unit name that precedes the @ symbol is specified as the Name property value.
2.4 Note about node and property names and character set
Nodes and attributes must use ASCII code A~Z, 0~9, commas, comma, underscores, plus signs, #号, question marks, and hyphens. In addition, the node name can also use ASCII code A~Z. The property name must be lowercase. The maximum string length for a node name and property name is 31.
2.5 Required Nodes and Propertites
The next step is to describe all the bindings that are currently needed. We strongly recommend that users export their custom bindings to the open Firmware as a document.
A) the root node
The root node needs to define the following properties:
-mode: Platform name/model
-#address-cells: root node Device address representation
-#size-cells: root node device size representation
-compatible: a compatible platform
Under the root node, you can also customize some of the platform's special properties, such as the serial number. If you have some properties that you need to customize, you can specify them in Vendor_name,custom_propertity_name, so that you don't confuse different platforms.
b) The/cpus node
This node is the parent node of all independent CPU nodes. It does not have any special properties, but we usually specify the #address-cells and #size-cells properties. This is usually:
#address-cells = <00000001>
#size-cells = <00000000>
It indicates that the CPU address is represented by a 32-bit numeric value, but does not represent a size (meaningless). When the kernel reads the Reg attribute of the CPU node, it is assumed to be parsed in this format.
c) the/cpus/* nodes
Under the/cpus node, we can define a node for each CPU on a machine. The name attribute is not strictly specified, but is usually named <architecture>,<core>. For example, Apple uses PowerPC, G5 to name, and IBM uses POWERPC,970FX to name it. As we can see, we typically use a compatible CPU schema name and a specified CPU model to name the Name property.
Required Properties:
-device_type: Only for "CPU"
-reg: The number of physical CPUs, which are typically a 32-bit value, and are used together with the unit name to form the full path of the CPU node. For example, a platform with two CPUs, the full path to the CPU node is as follows:
/cpus/powerpc,[email protected]
/cpus/powerpc,[email protected]
-d-cache-block-size:32 bit value representing L1 data buffer block Size (bytes)
-i-cache-block-size:32 bit value indicating L1 instruction buffer block size (bytes)
-d-cache-size:32 bit value representing L1 data cache size
-i-cache-size:32 bit value, indicating L1 instruction cache size
The block size refers to the size of the storage unit that the cache manages, that is, how many bytes of data are manipulated at a time.
Optional properties:
-timebase-frequency: Frequency value
-CLOCK-FREQUENCY:CPU Clock Frequency value
-d-cache-line-size: Like D-cache-block-size, just to be compatible with the previous definition
-i-cache-line-size: Like I-cache-block-size, just to be compatible with the previous definition
d) the/memory node (s)
To describe the physical memory layout, we need to define one or more momory nodes. You can specify multiple memory ranges in a memory node with the Reg attribute. You can also define multiple memory nodes as described separately. The unit addres that makes up the full path of the memory node is determined by the memory node that defines the memory range first. If a single memory node is used, it is usually @0.
Required Properties:
-device_type: Must be "memory"
-reg: Defines the memory ranges, which is a series of address/sizes pairs, and the format of address and size is defined by the #address-celles and #size-cells of the root node. For example:
00000000 00000000 00000000 80000000
00000001 00000000 00000001 00000000
The first range represents 0x80000000 bytes starting at 0 addresses, and the second range represents 0x100000000 bytes starting from 0x100000000. (Both the #address-cells and #size-cells are 2), which does not include the memory space of 2GB~4GB, which the kernel wants to do for other purposes.
e) The/chosen node
This node is typically used to store variable environment variables such as kernel parameters, default input, and so on.
Required Properties:
-bootargs: Kernel command-line arguments
-linux,stdout-path: Full path to the terminal console device
f) the/soc<socname> node
This node is used to represent a soc, and if you use a SOC as the processor, you must specify this node. The top-level attribute of the SOC node contains information that is valid for all devices on the SOC. The SOC node name should contain the unit address, which is the base address of the SOC's memory-mapped register group. The SOC node name starts with "Soc" and the remainder is populated with the SOC model. For example, the SOC node name for MPC8540 can be defined as "soc8054".
Required Properties:
-ranges: should be specified as 1, which describes how the memory-mapped register group addresses are translated.
-bus-frequency: The bus operating frequency that contains the SOC node, which is typically populated by the boot loader.
Exact model of-COMPATIBLE:SOC
Optional properties:
-reg:soc the address and size format of the Register group.
-#address-cells: Specifies the address format of the SOC sub-device.
-#size-CELLSL Specifies the size format of the SOC sub-device.
-#interrupt-cells: Defines the data bit width that represents the interrupt. Typically this value is 2, where 32 bits represent the interrupt number, and the other 32 bits indicate the interrupt detection bit and interrupt level. (Interrupt sense and level)
The SOC node may contain sub-nodes for each SOC device, and nodes that exist on the SOC but are used by specific platforms cannot be defined under the SOC node. The following sections detail how to accurately define device nodes on the SOC.
The SOC nodes of the MPC8540 platform are described below:
[Email protected] {
#address-cells = <1>;
#size-cells = <1>;
#interrupt-cells = <2>;
Device_type = "SOC";
ranges = <0x00000000 0xe0000000 0x00100000>
Reg = <0xe0000000 0x00003000>;
Bus-frequency = <0>;
}
This article is http://lxr.linux.no/linux+v3.19.1/Documentation/devicetree/ Booting-without-of.txt translation, but the compiler rules for the DTC compiler and some of the definition rules for some SOC node are not translated, but this part of the information can be found in the kernel documents inside the bindings.
Booting the LINUX/PPC kernel without Open Firmware