2. Hardware Description
System devicetrees can describe SoCs with multiple CPUs, possibly of different architectures, and possibly multiple processors in SMP configurations. System devicetrees additionally describe the address maps for each CPU in the SoC. This is necessary, for example, because a single device’s registers could be mapped to different addresses in different CPU memory maps. As another example, a device may only be accessible by a subset of the CPUs in the SoC.
This description is done using additional devicetree bindings defined in this section. The new bindings allow defining:
Multiple top level nodes which describe the CPUs on the SoC
Buses containing devices that do not automatically map to the parent address space (that is, may not be present in all CPU memory maps).
Interrupt mappings to multiple CPU clusters
See Section 2.5 for system devicetrees using these bindings.
2.1. CPU Cluster Binding
A CPU cluster is a node which describes one or more CPUs on the SoC that share an address space and other attributes. Typically, a CPU cluster node that describes multiple CPUs reflects multiple processors in an SMP configuration on the SoC.
See Section 2.2 for examples.
2.1.1. CPU Cluster Properties
CPU clusters should be represented in a system devicetree in top-level nodes using the following properties.
Property Name |
Usage |
Value Type |
Definition |
---|---|---|---|
|
R |
<string list> |
Value shall include “cpus,cluster”. See [DTSpec] §2.3.1. |
|
R |
|
Shall be 1. See [DTSpec] §2.3.5. |
|
R |
|
Shall be 0. See [DTSpec] §2.3.5. |
|
SD |
|
See Section 2.1.3. Specifies the addresses of hardware resources within the CPU cluster’s memory map. |
|
SD |
|
See Section 2.1.4. Specifies
the number of |
|
SD |
|
See Section 2.1.5. Specifies the
number of |
Usage legend: R=Required, O=Optional, OR=Optional but Recommended, SD=See Definition |
Note
The following additional standard properties defined in the
base specification are allowed but optional: model
,
phandle
, status
.
2.1.2. CPU Node Properties
The child nodes of a CPU cluster node describe the individual CPUs
within the cluster. They are represented identically to the
/cpus/cpu*
nodes in a standard devicetree. See [DTSpec] §3.8 and
§3.9 for details.
2.1.3. address-map
Property
Property |
|
---|---|
Value type |
|
Description |
Provides a means of defining a translation between the address space of a CPU cluster and the address space of the root node (recall that the root node is the parent node of the CPU cluster). The address-map property can be used to create a mapping between the address space of a CPU cluster node and the address spaces of hardware resources such as memory, devices, and buses containing other resources as child nodes. If a hardware resource in the system devicetree is not explicitly mapped into the CPU cluster’s address space using this property, it should be treated as if it is not addressable by the CPUs in the cluster. The address ranges defined by multiple quartets within a single address-map property may overlap. |
Example |
See Section 2.2. |
The format of the value of the address-map property is an arbitrary number of quartets, each of which specifies a mapping between the CPU cluster’s address space and another address space.
Within each quartet:
node-address is a physical address within the CPU cluster’s address space (the CPU cluster is the node in which the address-map property appears). This is the starting address within the CPU cluster’s memory map that the resources described by the quartet appear.
The number of cells used to represent the address is determined by the #ranges-address-cells property of the CPU cluster node (see Section 2.1.4).
ref-node is a phandle to the node describing the resources whose addresses are mapped into the CPU cluster’s address space. This describes the resources whose addresses are being mapped into the CPU cluster, either directly as a memory or device node, or indirectly as a bus node containing these.
root-node-address is a physical address within the root node’s address space. The number of cells used to represent the address is determined by the #address-cells property of the root node. This is the starting address, within the root node’s address space, of the resources whose addresses are being mapped in.
length is the size of the range in the CPU cluster’s address space. This is the length of the address range being mapped in.
The number of cells used to represent the size of the range is determined by the #ranges-size-cells property of the CPU cluster node (see Section 2.1.5).
Any resources with register block addresses fall in the range starting at root-node-address and ending length bytes later are visible to all CPUs within the cluster at the addresses specified by the mapping entry. Register blocks which appear after the end of the range are not visible. A register block which starts within the range but extends past the range’s end is truncated to fit within the range in the memory map of the CPU cluster node.
2.1.4. #ranges-address-cells
Property
Property |
|
---|---|
Value type |
|
Description |
The number of cells used to represent an address within the memory map of a CPU cluster node (the node in which the #ranges-address-cells property appears). This should be large enough to represent the maximum size of an address in the data model of the cluster’s CPU nodes. |
Example |
CPUs have 64-bit addresses: |
2.1.5. #ranges-size-cells
Property
Property |
|
---|---|
Value type |
|
Description |
The number of cells used to represent the size of a range of addresses in the memory map of a CPU cluster node (the node in which the #ranges-size-cells property appears), in bytes. This must be large enough to specify all address ranges within the CPU cluster node’s address-map property. |
Example |
32-bit address range sizes: |
2.2. Example CPU Clusters
2.2.1. Single-core Arm Cortex-M3
Here is a simplified example of a single CPU cluster with one CPU.
The root node has #address-cells set to 1.
cpu-cluster-arm {
#address-cells = <0x1>;
#size-cells = <0x0>;
compatible = "cpus,cluster";
#ranges-address-cells = <0x1>;
#ranges-size-cells = <0x1>;
address-map = <0x0 &code 0x0 0x40000>,
<0x20000000 &sram 0x0 0x10000>,
<0x40000000 &peripherals 0x1000 0x4000>;
cpu@0 {
compatible = "arm,cortex-m3";
device_type = "cpu";
reg = <0x0>;
};
};
The CPU’s address map contains:
a 256 KB code range, starting at address 0x0
a 128 KB SRAM range, starting at address 0x20000000
a 16 KB peripheral range, starting at address 0x40000000
The phandles to code
, sram
, and peripherals
refer to other
nodes in the devicetree which contain the resources of interest. Their
contents are not shown in this example.
2.2.2. Dual-core Arm Cortex-R5
Here is an example CPU cluster node with two CPU child nodes. This represents two Arm Cortex-R5 cores with shared memory and device access.
The root node has #address-cells set to 1.
cpus-cluster-r5 {
#address-cells = <0x1>;
#size-cells = <0x0>;
compatible = "cpus,cluster";
#ranges-address-cells = <0x1>;
#ranges-size-cells = <0x1>;
address-map = <0xf1000000 &amba 0xf1000000 0xeb00000>,
<0x0 &memory 0x0 0x80000000>;
cpu@0 {
compatible = "arm,cortex-r5";
device_type = "cpu";
reg = <0x0>;
};
cpu@1 {
compatible = "arm,cortex-r5";
device_type = "cpu";
reg = <0x1>;
};
};
Each of the two CPU’s address maps contains:
a 235 MiB range containing resources within an
amba
bus nodea 2 GiB memory range, starting at address 0x0
The addressable resources for each CPU are identical.
Again, the phandles to amba
and memory
refer to nodes elsewhere
in the devicetree that are not shown in this example.
2.3. Indirect Bus Binding
An indirect bus is a node in the system devicetree which acts as a resource container. This is similar to the “simple-bus” compatible value defined in [DTSpec] §4.5.
However, unlike “simple-bus” nodes, the resources inside an indirect bus do not map into the parent node’s address space. The devices on the bus can only be accessed directly by CPUs within CPU clusters whose address-map properties explicitly include the devices.
2.3.1. Indirect Bus Properties
CPU clusters should be represented in a system devicetree in top-level nodes using the following properties.
Property Name |
Usage |
Value Type |
Definition |
---|---|---|---|
|
R |
<string list> |
Value shall include “indirect-bus”. |
|
R |
|
See [DTSpec] §2.3.5. |
|
R |
|
See [DTSpec] §2.3.5. |
Usage legend: R=Required, O=Optional, OR=Optional but Recommended, SD=See Definition |
Note
Additional standard properties defined in the base specification §2.3 are allowed but optional.
2.4. The Default Cluster, /cpus
Within a system devicetree, the /cpus
node is the default CPU
cluster. As in a standard devicetree, this node can access the resources
contained in any “simple-bus” node directly. However, this node does not
have direct access to any resources defined within any “indirect-bus”
nodes by default. Within a system devicetree, the default cluster can
contain an address-map property if resources from indirect bus nodes
are visible to the corresponding CPUs.
2.5. Example System Devicetree Hardware Descriptions
2.5.1. Simple example
Here is a simplified example involving a single-core CPU cluster with three resource nodes. This is based on Section 2.2.1, but was extended to show the resource nodes.
cpu-cluster-arm {
#address-cells = <0x1>;
#size-cells = <0x0>;
compatible = "cpus,cluster";
#ranges-size-cells = <0x1>;
#ranges-address-cells = <0x1>;
address-map = <0x0 &code 0x0 0x40000>,
<0x20000000 &sram 0x0 0x10000>,
<0x40000000 &peripherals 0x1000 0x4000>;
cpu@0 {
compatible = "arm,cortex-m3";
device_type = "cpu";
reg = <0x0>;
};
};
code: code-bus {
compatible = "indirect-bus";
#address-cells = <1>;
#size-cells = <1>;
flash@0 {
compatible = "...";
reg = <0x0 0x40000>;
};
};
sram: sram-bus {
compatible = "indirect-bus";
#address-cells = <1>;
#size-cells = <1>;
sram@0 {
compatible = "mmio-sram";
reg = <0x0 0x10000>;
};
sram@10000 {
compatible = "mmio-sram";
reg = <0x10000 0x10000>;
};
};
peripherals: peripheral-bus {
compatible = "indirect-bus";
#address-cells = <1>;
#size-cells = <1>;
serial@0 {
compatible = "...";
reg = <0x0 0x1000>;
};
serial@2000 {
compatible = "...";
reg = <0x2000 0x1000>;
};
};
In this example:
the on-chip NOR flash device
flash@0
is visible starting at address 0x0 in the CPU cluster’s address spacethe SRAM
sram@0
is visible starting at 0x20000000the SRAM
sram@10000
is not visible to the CPU cluster, because its address-map property constrains thesram
address range to 0x10000 bytes in sizethe serial ports
serial@0
andserial@2000
are visible starting at 0x40001000 and 0x40003000, respectively
2.5.2. More complex example
Here is another example. Some properties have been omitted for brevity.
/* default cluster */
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
reg = <0>;
};
cpu@1 {
reg = <1>;
};
};
/* additional R5 cluster */
cpus_r5: cpus-cluster-r5 {
compatible = "cpus,cluster";
#address-cells = <1>;
#size-cells = <0>;
/* specifies address mappings */
address-map = <0xf9000000 &amba_rpu 0xf9000000 0x10000>;
cpu@0 {
reg = <0>;
};
cpu@1 {
reg = <1>;
};
};
amba_rpu: rpu-bus {
compatible = "indirect-bus";
};
In this example, there are:
two CPU cluster nodes; one of them is the default cluster,
/cpus
, and the other iscpus_r5
an indirect bus,
amba_rpu
which is not visible to the default clusterthe
cpus_r5
cluster can see theamba_rpu
bus, because it is explicitly mapped using the address-map property
As discussed above, devices only physically accessible from one of the two clusters should be placed under an “indirect-bus” appropriately.
For instance, we can extend the above to show how the interrupt tree and interrupt mapping can be described for multiple CPU clusters using the definitions in [DTSpec] §2.4:
/* default cluster */
cpus {
};
/* additional R5 cluster */
cpus_r5: cpus-cluster-r5 {
compatible = "cpus,cluster";
/* specifies address mappings */
address-map = <0xf9000000 &amba_rpu 0xf9000000 0x10000>;
};
/* bus only accessible by cpus */
amba_apu: apu-bus {
compatible = "simple-bus";
gic_a72: interrupt-controller@f9000000 {
};
};
/* bus only accessible by cpus_r5 */
amba_rpu: rpu-bus {
compatible = "indirect-bus";
gic_r5: interrupt-controller@f9000000 {
};
};
Note that:
gic_a72
is visible to/cpus
, but not tocpus_r5
, becauseamba_apu
is not present in the address-map property ofcpus_r5
.gic_r5
is visible tocpus_r5
, because it is present in the address-map property ofcpus_r5
gic_r5
is not visible to/cpus
because indirect bus nodes do not automatically map to the parent address space, and/cpus
doesn’t have an address-map property
Relying on the fact that each interrupt controller is visible to its CPU cluster node, it is possible to express interrupt routing from a device to multiple clusters. For instance:
amba: axi-bus {
compatible = "simple-bus";
#address-cells = <2>;
#size-cells = <2>;
ranges;
#interrupt-cells = <3>;
interrupt-map-pass-thru = <0xffffffff 0xffffffff 0xffffffff>;
interrupt-map-mask = <0x0 0x0 0x0>;
interrupt-map = <0x0 0x0 0x0 &gic_a72 0x0 0x0 0x0>,
<0x0 0x0 0x0 &gic_r5 0x0 0x0 0x0>;
can0: can@ff060000 {
compatible = "xlnx,canfd-2.0";
reg = <0x0 0xff060000 0x0 0x6000>;
interrupts = <0x0 0x14 0x1>;
};
};
In this example, all devices under amba
, including can@ff060000
,
have their interrupts routed to both gic_r5
and gic_a72
.