http://devicetree.org/Device_Tree_Usage
Device Tree Usage
From FDTWiki
This
page walks through how to write a device tree for a new machine. For a
full technical description of device tree data format, refer to the ePAPR
specification. The ePAPR specification covers a lot more detail than
the basic topics covered on this page, please refer to it for more
advanced usage that isn't covered by this page.
Basic Data Format
The device tree is a simple tree structure of nodes and properties.
Properties are key-value pairs, and node may contain both properties
and child nodes. For example, the following is a simple tree in the .dts
format:
/ {
node1 {
a-string-property = "A string";
a-string-list-property = "first string", "second string";
a-byte-data-property = [0x01 0x23 0x34 0x56];
child-node1 {
first-child-property;
second-child-property = <1>;
a-string-property = "Hello, world";
};
child-node2 {
};
};
node2 {
an-empty-property;
a-cell-property = <1 2 3 4>; /* each number (cell) is a uint32 */
child-node1 {
};
};
};
This tree is obviously pretty useless because it doesn't describe
anything, but it does show the structure of nodes an properties. There
is:
- a single root node: "
/
"
- a couple of child nodes: "
node1
" and "node2
"
- a couple of children for node1: "
child-node1
" and "child-node2
"
- a bunch of properties scattered through the tree.
Basic Concepts
To understand how the device tree is used, we will start with a
simple machine and build up a device tree to describe it step by step.
Sample Machine
Consider the following imaginary machine (loosely based on ARM
Versatile), manufactured by "Acme" and named "Coyote's Revenge":
- One 32bit ARM CPU
- processor local bus attached to memory mapped serial port,
spi bus controller, i2c controller, interrupt controller, and external
bus bridge
- 256MB of SDRAM based at 0
- 2 Serial ports based at 0x101F1000 and 0x101F2000
- GPIO controller based at 0x101F3000
- SPI controller based at 0x10170000 with following devices
- MMC slot with SS pin attached to GPIO #1
- External bus bridge with following devices
- SMC SMC91111 Ethernet device attached to external bus based
at 0x10100000
- i2c controller based at 0x10160000 with following devices
- Maxim DS1338 real time clock. Responds to slave address
1101000 (0x58)
- 64MB of NOR flash based at 0x30000000
Initial structure
The first step is to lay down a skeleton structure for the machine.
This is the bare minimum structure required for a valid device tree. At
this stage you want to uniquely identify the machine.
/ {
compatible = "acme,coyotes-revenge";
};
compatible
specifies the name of the system. It
contains a string in the form "<manufacturer>,<model>. It
is important to specify the exact device, and to include the
manufacturer name to avoid namespace collisions. Since the operating
system will use the compatible
value to make decisions
about how to run on the machine, it is very important to put correct
data into this property.
Theoretically, compatible is all the data an OS needs to
uniquely identify a machine. If all the machine details are hard coded,
then the OS could look specifically for "acme,coyotes-revenge" in the
top level compatible
property.
CPUs
Next step is to describe for each of the CPUs. A container node
named "cpus" is added with a child node for each CPU. In this case the
system is a dual-core Cortex A9 system from ARM.
/ {
compatible = "acme,coyotes-revenge";
cpus {
c...@0 {
compatible = "arm,cortex-a9";
};
c...@1 {
compatible = "arm,cortex-a9";
};
};
};
The compatible property in each cpu node is a string that specifies
the exact cpu model in the form <manufacturer>,<model>
,
just like the compatible property at the top level.
More properties will be added to the cpu nodes later, but we first
need to talk about more of the basic concepts.
Node Names
It is worth taking a moment to talk about naming conventions. Every
node must have a name in the form <name>[@<unit-address>
].
<name>
is a simple ascii string and can be up
to 31 characters in length. In general, nodes are named according to
what kind of device it represents. ie. A node for a 3com Ethernet
adapter would be use the name ethernet
, not 3com509
.
The unit-address is included if the node describes a device with
an address. In general, the unit address is the primary address used to
access the device, and is listed in the node's reg
property. We'll cover the reg property later in this document.
Sibling nodes must be uniquely named, but it is normal for more
than one node to use the same generic name so long as the address is
different (ie, ser...@101f1000 & ser...@101f2000).
See section 2.2.1 of the ePAPR spec for full details about node
naming.
Devices
Every device in the system is represented by a device tree node. The
next step is to populate the tree with a node for each of the devices.
For now, the new nodes will be left empty until we can talk about how
address ranges and irqs are handled.
/ {
compatible = "acme,coyotes-revenge";
cpus {
c...@0 {
compatible = "arm,cortex-a9";
};
c...@1 {
compatible = "arm,cortex-a9";
};
};
ser...@101f0000 {
compatible = "arm,pl011";
};
ser...@101f2000 {
compatible = "arm,pl011";
};
g...@101f3000 {
compatible = "arm,pl061";
};
interrupt-control...@10140000 {
compatible = "arm,pl190";
};
s...@10115000 {
compatible = "arm,pl022";
};
external-bus {
ether...@0,0 {
compatible = "smc,smc91c111";
};
i...@1,0 {
compatible = "acme,a1234-i2c-bus";
r...@58 {
compatible = "maxim,ds1338";
};
};
fl...@2,0 {
compatible = "samsung,k8f1315ebm", "cfi-flash";
};
};
};
In this tree, a node has been added for each device in the system,
and the hierarchy reflects the how devices are connected to the system.
ie. devices on the extern bus are children of the external bus node,
and i2c devices are children of the i2c bus controller node. In
general, the hierarchy represents the view of the system from the
perspective of the CPU.
This tree isn't valid at this point. It is missing information
about connections between devices. That data will be added later.
Some things to notice in this tree:
- Every device node has a
compatible
property.
- The flash node has 2 strings in the compatible property. Read on
to the next section to learn why.
- As mentioned earlier, node names reflect the type of device,
not the particular model. See section 2.2.2 of the ePAPR spec for a
list of defined generic node names that should be used wherever
possible.
Understanding the compatible
Property
Every node in the tree that represents a device is required to have
the compatible
property. compatible
is the
key an operating system uses to decide which device driver to bind to a
device.
compatible
is a list of strings. The first string in
the list specifies the exact device that the node represents in the
form "<manufacturer>,<model>
. The following
strings represent other devices that the device is compatible
with.
For example, the Freescale MPC8349 System on Chip (SoC) has a
serial device which implements the National Semiconductor ns16550
register interface. The compatible property for the MPC8349 serial
device should therefore be: compatible = "fsl,mpc8349-uart",
"ns16550"
. fsl,mpc8349-uart
specifies the exact
device, and ns16550
states that it is register-level
compatible with the older device.
Note: ns16550
doesn't have a manufacturer prefix
purely for historical reasons. All new compatible values should use the
manufacturer prefix.
This practice allows existing device drivers to be bound to a newer
device, while still uniquely identifying the exact hardware.
Warning: Don't use wildcard compatible values, like
"fsl,mpc83xx-uart" or similar. Silicon vendors will invariably make a
change that breaks your wildcard assumptions the moment it is too late
to change it. Instead, choose a specific silicon implementations and
make all subsequent silicon compatible with it.
How Addressing Works
Devices that are addressable use the following properties to encode
address information into the device tree:
-
reg
-
#address-cells
-
#size-cells
Each addressable device gets a reg
which is a list of
tuples in the form reg = <address1 length1 [address2 length2]
[unit-address3 length3] ... >
.
Each tuple represents an address range used by the device. Each address
value is a list of one or more 32 bit integers called cells.
Similarly, the length value can either be a list of cells, or empty.
Since both the address and length fields are variable of variable
size, the #address-cells
and #size-cells
properties are used to state how many cells are in each field. To see
how this all works, lets add the addressing properties to the sample
device tree, starting with the CPUs.
CPU addressing
The CPU nodes represent the simplest case when talking about
addressing. Each CPU is assigned a single unique ID, and there is no
size associated with CPU ids.
cpus {
#address-cells = <1>;
#size-cells = <0>;
c...@0 {
compatible = "arm,cortex-a9";
reg = <0>;
};
c...@1 {
compatible = "arm,cortex-a9";
reg = <1>;
};
};
In the cpus
node, #address-cells
is set
to 1, and #size-cells
is set to 0. This means that child reg
values are a single uint32 that represent the address with no size
field. In this case, the two cpus are assigned addresses 0 and 1. #size-cells
is 0 for cpu nodes because each cpu is only assigned a single address.
You'll also notice that the reg
value matches the
value in the node name. By convention, if a node has a reg
property, then the node name must include the unit-address, which is
the first address value in the reg
property.
Memory Mapped Devices
Instead of single address values like found in the cpu nodes, a
memory mapped device is assigned a range of addresses that it will
respond to. #size-cells
is used to state how large the
length field is in each child reg
tuple. In the following example, each address value is 1 cell (32
bits), and each length value is also 1 cell, which is typical on 32 bit
systems. 64 bit machines may use a value of 2 for #address-cells and
#size-cells to get 64 bit addressing in the device tree.
/ {
#address-cells = <1>;
#size-cells = <1>;
...
ser...@101f0000 {
compatible = "arm,pl011";
reg = <0x101f0000 0x1000 >;
};
ser...@101f2000 {
compatible = "arm,pl011";
reg = <0x101f2000 0x1000 >;
};
g...@101f3000 {
compatible = "arm,pl061";
reg = <0x101f3000 0x1000
0x101f4000 0x0010>;
};
interrupt-control...@10140000 {
compatible = "arm,pl190";
reg = <0x10140000 0x1000 >;
};
s...@10115000 {
compatible = "arm,pl022";
reg = <0x10115000 0x1000 >;
};
...
};
Each device is assigned a base address, and the size of the region
it is assigned. The GPIO device address in this example is assigned two
address ranges; 0x101f3000...0x101f3fff and 0x101f4000..0x101f400f.
Some devices live on a bus with a different addressing scheme.
For example, a device can be attached to an external bus with discrete
chip select lines. Since each parent node defines the addressing domain
for its children, the address mapping can be chosen to best describe
the system. The code below show address assignment for devices attached
to the external bus with the chip select number encoded into the
address.
external-bus {
#address-cells = <2>
#size-cells = <1>;
ether...@0,0 {
compatible = "smc,smc91c111";
reg = <0 0 0x1000>;
};
i...@1,0 {
compatible = "acme,a1234-i2c-bus";
reg = <1 0 0x1000>;
r...@58 {
compatible = "maxim,ds1338";
};
};
fl...@2,0 {
compatible = "samsung,k8f1315ebm", "cfi-flash";
reg = <2 0 0x4000000>;
};
};
The external-bus
uses 2 cells for the address value;
one for the chip select number, and one for the offset from the base of
the chip select. The length field remains as a single cell since only
the offset portion of the address needs to have a range. So, in this
example, each reg
entry contains 3 cells; the chipselect
number, the offset, and the length.
Since the address domains are contained to a node and its
children, parent nodes are free to define whatever addressing scheme
makes sense for the bus. Nodes outside of the immediate parent and
child nodes do not normally have to care about the local addressing
domain, and addresses have to be mapped to get from one domain to
another.
Non Memory Mapped Devices
Other devices are not memory mapped on the processor bus. In the
case of i2c devices, each device is assigned an address, but there is
no length or range associated with it. This looks much the same as CPU
address assignments.
i...@1,0 {
compatible = "acme,a1234-i2c-bus";
#address-cells = <1>;
#size-cells = <0>;
reg = <1 0 0x1000>;
r...@58 {
compatible = "maxim,ds1338";
reg = <58>;
};
};
Ranges (Address Translation)
We've talked about how to assign addresses to devices, but at this
point those addresses are only local to the device node. It doesn't yet
describe how to map from those address to an address that the CPU can
use.
The root node always describes the CPU's view of the address
space. Child nodes of the root are already using the CPU's address
domain, and so do not need any explicit mapping. For example, the
ser...@101f0000 device is directly assigned the address 0x101f0000.
For nodes that are not direct children of the root, like the
devices on the external bus, do not use the CPU's address domain, so in
order to get a memory mapped address, the device tree must specify how
to translate addresses from one domain to another. The ranges
property is used for this purpose.
Here is the sample device tree with the ranges property added.
/ {
compatible = "acme,coyotes-revenge";
#address-cells = <1>;
#size-cells = <1>;
...
external-bus {
#address-cells = <2>
#size-cells = <1>;
ranges = <0 0 0x10100000 0x10000 // Chipselect 1, Ethernet
1 0 0x10160000 0x10000 // Chipselect 2, i2c controller
2 0 0x30000000 0x1000000>; // Chipselect 3, NOR Flash
ether...@0,0 {
compatible = "smc,smc91c111";
reg = <0 0 0x1000>;
};
i...@1,0 {
compatible = "acme,a1234-i2c-bus";
#address-cells = <1>;
#size-cells = <0>;
reg = <1 0 0x1000>;
r...@58 {
compatible = "maxim,ds1338";
reg = <58>;
};
};
fl...@2,0 {
compatible = "samsung,k8f1315ebm", "cfi-flash";
reg = <2 0 0x4000000>;
};
};
};
ranges
is a list of address translations. Each entry in
the ranges table is a tuple containing the child address, the parent
address, and the size of the region in the child address space. The
size of each field is determined by taking the child's #address-cells
value, the parent's #address-cells
value, and the child's
#size-cells
value. For the external bus in our example, the child address is 2
cells, the parent address is 1 cell, and the size is also 1 cell. Three
ranges are being translated:
- Offset 0 from chip select 0 is mapped to address range
0x10100000..0x1010ffff
- Offset 0 from chip select 1 is mapped to address range
0x10160000..0x1016ffff
- Offset 0 from chip select 2 is mapped to address range
0x30000000..0x10000000
Alternately, if the parent and child address spaces are identical,
then a node can instead add an empty ranges
property. The presence of an empty ranges property means addresses in
the child address space are mapped 1:1 onto the parent address space.
You might ask why address translation is used at all when it
could all be written with 1:1 mapping. Some busses (like PCI) have
entirely different address spaces whose details need to be exposed to
the operating system. Others have DMA engines which need to know the
real address on the bus. Sometimes devices need to be grouped together
because they all share the same software programmable physical address
mapping. Whether or not 1:1 mappings should be used depends a lot on
the information needed by the Operating system, and on the hardware
design.
You should also notice that there is no ranges
property in the i...@1,0 node. The reason for this is that unlike the
external bus, devices on the i2c bus are not memory mapped on the CPU's
address domain. Instead, the CPU indirectly accesses the r...@58 device
via the i...@1,0 device. The lack of a ranges
property
means that a device cannot be directly accessed by any device other
than it's parent.
How Interrupts Work
Unlike address range translation which follows the natural structure
of the tree,
Interrupt signals can originate from and terminate on any device
in a machine. Unlike device addressing which is naturally expressed in
the device tree, interrupt signals are expressed as links between nodes
independent of the tree. Four properties are used to describe interrupt
connections:
-
interrupt-controller
- An empty property declaring
a node as a device that receives interrupt signals
-
#interrupt-cells
- This is a property of the
interrupt controller node. It states how many cells are in an interrupt
specifier for this interrupt controller (Similar to #address-cells
and #interrupt-cells
).
-
interrupt-parent
- A property of a device node
containing a phandle
to the interrupt controller that it is attached to. Nodes that do not
have an interrupt-parent property can also inherit the property from
their parent node.
-
interrupts
- A property of a device node
containing a list of interrupt specifiers, one for each
interrupt output signal on the device.
An interrupt specifier is one or more cells of data (as
specified by #interrupt-cells) that specifies which interrupt input the
device is attached to. Most devices only have a single interrupt output
as shown in the example below, but it is possible to have multiple
interrupt outputs on a device. The meaning of an interrupt specifier
depends entirely on the binding for the interrupt controller device.
Each interrupt controller can decide how many cells it need to uniquely
define an interrupt input.
The following code adds interrupt connections to our Coyote's
Revenge example machine:
/ {
compatible = "acme,coyotes-revenge";
#address-cells = <1>;
#size-cells = <1>;
interrupt-parent = <&intc>;
cpus {
#address-cells = <1>;
#size-cells = <0>;
c...@0 {
compatible = "arm,cortex-a9";
reg = <0>;
};
c...@1 {
compatible = "arm,cortex-a9";
reg = <1>;
};
};
ser...@101f0000 {
compatible = "arm,pl011";
reg = <0x101f0000 0x1000 >;
interrupts = < 1 0 >;
};
ser...@101f2000 {
compatible = "arm,pl011";
reg = <0x101f2000 0x1000 >;
interrupts = < 2 0 >;
};
g...@101f3000 {
compatible = "arm,pl061";
reg = <0x101f3000 0x1000
0x101f4000 0x0010>;
interrupts = < 3 0 >;
};
intc: interrupt-control...@10140000 {
compatible = "arm,pl190";
reg = <0x10140000 0x1000 >;
interrupt-controller;
#interrupt-cells = <2>;
};
s...@10115000 {
compatible = "arm,pl022";
reg = <0x10115000 0x1000 >;
interrupts = < 4 0 >;
};
external-bus {
#address-cells = <2>
#size-cells = <1>;
ranges = <0 0 0x10100000 0x10000 // Chipselect 1, Ethernet
1 0 0x10160000 0x10000 // Chipselect 2, i2c controller
2 0 0x30000000 0x1000000>; // Chipselect 3, NOR Flash
ether...@0,0 {
compatible = "smc,smc91c111";
reg = <0 0 0x1000>;
interrupts = < 5 2 >;
};
i...@1,0 {
compatible = "acme,a1234-i2c-bus";
#address-cells = <1>;
#size-cells = <0>;
reg = <1 0 0x1000>;
interrupts = < 6 2 >;
r...@58 {
compatible = "maxim,ds1338";
reg = <58>;
interrupts = < 7 3 >;
};
};
fl...@2,0 {
compatible = "samsung,k8f1315ebm", "cfi-flash";
reg = <2 0 0x4000000>;
};
};
};
Some things to notice:
- The machine has a single interrupt controller,
interrupt-control...@10140000.
- The label 'intc:' has been added to the interrupt controller
node, and the label was used to assign a phandle to the
interrupt-parent property in the root node. This interrupt-parent value
becomes the default for the system because all child nodes inherit it
unless it is explicitly overridden.
- Each device uses an interrupt property to specify a different
interrupt input line.
- #interrupt-cells is 2, so each interrupt specifier has 2
cells. This example uses the common pattern of using the first cell to
encode the interrupt line number, and the second cell to encode flags
such as active high vs. active low, or edge vs. level sensitive. For
any given interrupt controller, refer to the controller's binding
documentation to learn how the specifier is encoded.
Device Specific Data
Beyond the common properties, arbitrary properties and child nodes
can be added to node. Anything data needed by the operating system can
be added as long as some rules are followed.
First, new device-specific property names should use a
manufacture prefix so that they don't conflict with existing standard
property names.
Second, the meaning of the properties and child nodes must be
documented in a binding so that a device driver author knows how to
interpret the data. A binding documents what a particular compatible
value means, what properties it should have, what child nodes it might
have, and what device it represents. Each unique compatible
value should have its own binding (or claim compatibility with another
compatible value). Bindings for new devices are documented in this
wiki. See the Main Page for a description of the documentation
format and review process.
Third, post new bindings for review on the
devicetree-disc...@lists.ozlabs.org mailing list. Reviewing new
bindings catches a lot of common mistakes that will cause problems in
the future.
Special Nodes
aliases
Node
A specific node is normally referenced by the full path, like /external-bus/ether...@0,0
,
but that gets cumbersome when what a user really wants to know is,
"which device is eth0?" The aliases
node can be used to
assign a short alias to a full device path. For example:
aliases {
ethernet0 = ð0;
serial0 = &serial0;
};
The operating system is welcome to use the aliases when assigning an
identifier to a device.
You'll notice a new syntax used here. The property =
&label;
syntax assigns the full node path referenced
by the label as a string property. This is different from the phandle
= < &label >;
form used earlier which inserts a
phandle value into a cell.
chosen
Node
The chosen
node doesn't represent a real device, but
serves as a place for passing data between firmware and the operating
system, like boot arguments. Data in the chosen node does not represent
the hardware. Typically the chosen node is left empty in .dts source
files and populated at boot time.
In our example system, firmware might add the following to the
chosen node:
chosen {
bootargs = "root=/dev/nfs rw nfsroot=192.168.1.1 console=ttyS0,115200";
};