The first step is to build a basic structure for this model mechanism, which is the most basic structure of an effective device tree. At this stage you need to uniquely identify the machine.
/{
Compatible= "Marvell, armada38x"
};compatible Specifies the name of the system. It contains a string of "< manufacturer >,< model >" form. It is important to specify an exact device and include the manufacturer's name to avoid namespace collisions. Because the operating system uses the value of compatible to determine how to run on the machine, it is important to set this property correctly.
The next step is to describe each CPU. Add a container node named "CPUs" first, and then add child nodes for each CPU separately. Specifically to our case is an ARM of the dual-core Cortex A9 system
/{
Compatible= "Marvell, armada38x";
cpus{
[Email protected] {
compatible = "ARM,CORTEX-A9";
};
[Email protected] {
compatible = "ARM,CORTEX-A9";
};
};
The compatible property of each CPU node is a string in the form of < manufacturer >,< Model >, and specifies the exact CPU, just like the compatible property on the top level
node name : It's time to take a moment to discuss naming conventions. Each node must have a name of "< name >[@< device address;]" form.
1). Name > is a simple ASCII string of no more than 31 bits. In general, the naming of a node should be based on what kind of device it embodies. For example, a 3com Ethernet adapter node should be named Ethernet, not 3com509.
2). If the device described by the node has an address, the device address (unit-address) should also be added. Typically, the device address is used to access the primary address of the device, and the address is also listed in the Reg attribute of the node
3). Peer node naming must be unique, but multiple nodes can use the same generic name as long as the address is different (e.g. [email protected] and [email protected])
device : Each device in the system is represented as a device tree node. So the device node should be populated with the device tree next. Now, knowing that we are discussing how to address and how interrupt requests are handled, these new nodes will always be empty.
/ {
compatible = "Acme,coyotes-revenge";
CPUs {
[Email protected] {
compatible = "ARM,CORTEX-A9";
};
[Email protected] {
compatible = "ARM,CORTEX-A9";
};
};
[Email protected] {
compatible = "arm,pl011";
};
[Email protected] {
compatible = "arm,pl011";
};
[Email protected] {
compatible = "arm,pl061";
};
[Email protected] {
compatible = "arm,pl190";
};
[Email protected] {
compatible = "arm,pl022";
};
External-bus {
[Email protected],0 {
compatible = "smc,smc91c111";
};
[Email protected],0 {
compatible = "Acme,a1234-i2c-bus";
[Email protected] {
compatible = "maxim,ds1338";
};
};
[Email protected],0 {
compatible = "SAMSUNG,K8F1315EBM", "Cfi-flash";
};
};
In this tree, a node has been added for each device in the system, and this hierarchy also reflects how the device is connected to the system. For example, the device on the external bus is the child node of the external bus node, and the I²C device is the child node of the I²c bus node. Typically, this hierarchy shows a system view of the CPU perspective. Now this tree is still invalid because it lacks information about the interconnection between devices. This information will be added later.
In this tree, you should pay attention to these things:
Each device node has a compatible property,
The Compatible property of a flash (flash) node is composed of two strings. For details, please read the next section
Understanding Compatible Properties:
1). Each node in the tree that represents a device requires a compatible attribute. The Compatible property is a key factor that the operating system uses to determine which device driver to use to bind to a device.
2). Compatible is a list of strings in which the first string specifies the exact device represented by this node, which is in the format: "< manufacturer >,< model >". The remaining strings represent other devices that are compatible with them.
3). Freescale MPC8349 on-chip system (SoC) has a serial device that implements the Register interface of the National semiconductor ns16550, then the compatible attribute of the MPC8349 serial device should be: compatible = "FSL, Mpc8349-uart "," ns16550 ". Here, Mpc8349-uart specifies the exact device, while ns16550 indicates that it is compatible with the register level of the U.S. National Semiconductor ns16550 UART
4). Do not use compatible values with wildcard characters, such as "Fsl,mpc83xx-uart" or similar cases. The chip provider will not make any changes that can easily break your wildcard guess, which is already too late to change. Instead, you should select a specific chip and then all subsequent chips are compatible with it.
How to Address:
1> addressable devices use the following properties to encode address information into the device tree
Reg
#address-cells
#size-cells
2> Each addressable device has a tuple list of Reg, in the form of a tuple: REG = < address 1 length 1 [Address 2 length 2] [address 3 length 3] ... >. Each tuple represents a range of addresses used by the device. Each address value is one or more 32-bit integer lists, called cells. Similarly, the length value can be either a cell list or empty.
3> because the address and length fields are variable-sized variables, the #address-cells and #size-cells properties of the parent node are used to declare the number of cells for each field. In other words, the correct interpretation of a Reg property requires the use of the parent node's #address-cells and #size-cells values. To know how this all works, we'll add the Address property to the model machine, starting with the CPU.
CPU Addressing:
The
CPU node represents one of the simplest examples of addressing. Each CPU is assigned a unique ID and does not have the size information associated with the CPU ID.
CPUs {
#address-cells = <1>;
#size-cells = <0>;
[email protected] {
compatible = "Arm,co Rtex-a9 ";
reg = <0>;
};
[email protected] {
compatible = "Arm,co Rtex-a9 ";
reg = <1>;
};
; In the CPU node, #address-cells is set to 1, #size-cells is set to 0. This means that the reg value of the child node is a single uint32, which is an address that does not contain the size field, and the addresses assigned to these two CPUs are 0 and 1. The #size-cells of the CPU nodes is 0 because only a single address is assigned to each CPU. You may also notice that the value of Reg is the same as the node name. As a rule, if a node has a reg attribute, the name of the node must contain the device address, which is the first address value in the Reg attribute
Memory-Mapped devices:
Unlike a single address value in a CPU node, an address range should be assigned to a memory-mapped device. #size-cells declares the size of the length field in the Reg tuple for each child node. In the following example, each address value is 1 cells (32 bits), and each length value is 1 cell, which is a typical 32-bit system. A 64-bit machine can use a value of 2 #address-cells and #size-cells to obtain 64-bit addressing in the device tree.
/ {
#address-cells = <1>;
#size-cells = <1>;
...
[Email protected] {
compatible = "arm,pl011";
reg = <0x101f0000 0x1000 >;
};
[Email protected] {
compatible = "arm,pl011";
reg = <0x101f2000 0x1000 >;
};
[Email protected] {
compatible = "arm,pl061";
Reg = <0x101f3000 0x1000
0x101f4000 0x0010>;
};
[Email protected] {
compatible = "arm,pl190";
reg = <0x10140000 0x1000 >;
};
[Email protected] {
compatible = "arm,pl022";
reg = <0x10115000 0x1000 >;
};
...
Each device is assigned a base address and the size of the area. In this example, the GPIO is assigned two address ranges: 0x101f3000 ... 0x101f3fff and 0x101f4000. 0x101f400f.
Some devices that hang on the bus have different addressing schemes. For example, a device with a separate line selection can also be connected to an external bus. Because the parent node defines the Address field for its child nodes, it is possible to choose a different address map to describe the system most appropriately. The following code shows the address assignment where the device is connected to an external bus and encodes its slice number into the address
External-bus {
#address-cells = <2>
#size-cells = <1>;
[Email protected],0 {
compatible = "smc,smc91c111";
Reg = <0 0 0x1000>;
};
[Email protected],0 {
compatible = "Acme,a1234-i2c-bus";
Reg = <1 0 0x1000>;
[Email protected] {
compatible = "maxim,ds1338";
};
};
[Email protected],0 {
compatible = "SAMSUNG,K8F1315EBM", "Cfi-flash";
Reg = <2 0 0x4000000>;
};
The address value of the external bus uses two cells, one for the chip selection, and the other for the offset of the slice base. The Length field is also a single cell, because only the offset portion of the address requires a range amount. So, in this example, each REG entry has three cells: the slice number, the offset, and the length.
Because the Address field is contained in a node and its child nodes, the parent node is free to define any addressing scheme that is meaningful to the bus. Those nodes that are outside the immediate parent and child nodes typically do not care about the local address domain, and addresses should be mapped from one domain to another
Chosen node:
The chosen node does not represent a real device, but as a place to pass data between the firmware and the operating system, such as boot parameters. The data in the chosen node also does not represent hardware. Typically, the chosen node is empty in the. DTS source file and is populated at startup.
Chosen {
Bootargs = "Root=/dev/nfs rw nfsroot=192.168.1.1 console=ttys0,115200";
};
...................
....................
Writing Device Tree DTS