Device Tree Mysteries

Top Device Tree page

Some subjects are not documented anywhere, or the documentation is cryptic or incomplete. This page will try to provide some insights into those subjects.

device creation, driver binding, probing
See [[Media:Rowand--devicetree_kernel_internals.pdf | devicetree: Kernel Internals and Practical Troubleshooting [PDF] ]] , ELC Europe 2014 by Frank Rowand.

Assign property value to a signed integer
There is no signed data type for property values in device tree source files. However, recent versions of the dtc compiler allow specifying negative values (see Device Tree source : Signed Property Values for more information).

A common incorrect pattern in Linux drivers is to read a u32 property value into a signed variable.

Example driver code: int rc; struct device_node *np; int a, b, c, d;

np = of_find_node_by_name(NULL, "node_xxx"); pr_err("np = %p\n", np); rc = of_property_read_u32(np, "a", &a); pr_err("rc = %d  a = %11d\n", rc, a);

rc = of_property_read_u32(np, "b", &b); pr_err("rc = %d  b = %11d\n", rc, b);

rc = of_property_read_u32(np, "c", &c); pr_err("rc = %d  c = %11d\n", rc, c);

rc = of_property_read_u32(np, "d", &d); pr_err("rc = %d  d = %11d\n", rc, d);

Device tree source, providing values for the properties a, b, c, and d:       node_xxx { a = ; b = ; c = ; d = ; };

The console output from the example driver code shows some negative property values, even though the device tree source contains only positive values. This is because the integer variables treat the data as 2's complement values: np = eeff8e88 rc = 0  a =  2147483647 rc = 0  b = -2147483648 rc = 0  c = -2147483647 rc = 0  d = -2147483646

There was no compiler warning that the address of an int instead of the address of a u32 was passed to of_property_read_u32.

However, if the address of a u32 is passed to of_property_read_u32, and then the value of the u32 is assigned to an integer variable (as in the following example), then the compiler will warn that there is a possible problem. But to see this warning, W=3 has to be provided to the make command.

142        int rc; 143        struct device_node *np; 144        int a, b, c, d; 145         u32 val; 146 147        np = of_find_node_by_name(NULL, "node_xxx"); 148        pr_err("np = %p\n", np); 149 150        rc = of_property_read_u32(np, "a", &val); 151        a = val; 152        pr_err("rc = %d   a = %11d\n", rc, a); 153 154        rc = of_property_read_u32(np, "b", &val); 155        b = val; 156        pr_err("rc = %d   b = %11d\n", rc, b); 157 158        rc = of_property_read_u32(np, "c", &val); 159        c = val; 160        pr_err("rc = %d   c = %11d\n", rc, c); 161 162        rc = of_property_read_u32(np, "d", &val); 163        d = val; 164        pr_err("rc = %d   d = %11d\n", rc, d);

$ make W=3 drivers/misc/xxx.o

drivers/misc/xxx.c:151:2: warning: conversion to 'int' from 'u32' may change the sign of the result [-Wsign-conversion] drivers/misc/xxx.c:155:2: warning: conversion to 'int' from 'u32' may change the sign of the result [-Wsign-conversion] drivers/misc/xxx.c:159:2: warning: conversion to 'int' from 'u32' may change the sign of the result [-Wsign-conversion] drivers/misc/xxx.c:163:2: warning: conversion to 'int' from 'u32' may change the sign of the result [-Wsign-conversion]

Signed Property Values
ePAPR Version 1.1 lists the following data types for properties:



There is no mention of a signed data type.

However, recent versions of the dtc compiler do allow signed 32 bit object as data values, as a result of adding integer expression support. The side effect of this is that negative constants must be enclosed in parenthesis, for example: (-327). For further details on this notation, see http://lists.infradead.org/pipermail/linux-arm-kernel/2013-April/159681.html

http://lists.infradead.org/pipermail/linux-arm-kernel/2013-April/159681.html

How to represent negative values for device tree property David Gibson Tue Apr 2 02:17:47 EDT 2013

Using signed property data values can lead to errors in device tree source files that the dtc compiler can not detect. In this example, the values from the device tree source file: my-array = < (-2147483648)                  (-2147483647)                   (-1)                            0                               1                               2147483647                      2147483648            2147483649            >; will be 2's complement values on the target, if the kernel code properly interprets them as signed: -2147483648 -2147483647        -1                   0                    1           2147483647 -2147483648 -2147483647

'''Notice how the integer values wrap from the most positive to the most negative, even though the unsigned 32 bit values are monotonically increasing. In this example, dtc will not warn that the two values 2147483648 and 2147483649 will be negative values on the target system.''' '''It is not sufficient to specify a minus sign in the device tree source. The kernel code that reads the property value must also explicitly treat the value as a 32 bit 2's complement value instead of as an unsigned 32 bit value.''' For example, the kernel code can read the property value with.

cryptic
The [[Media:Power_ePAPR_APPROVED_v1.1.pdf | ePAPR]] tells us

2.3.3 phandle

Property: phandle Value type: Description: The phandle property specifies a numerical identifier for a node that is unique within the device tree. The phandle property value is used by other nodes that need to refer to the node associated with the property.

Example:

See the following device tree excerpt:

pic@10000000 { phandle = < 1 >; interrupt-controller; };

A phandle value of 1 is defined. Another device node could reference the pic node with a  phandle value of 1:

interrupt-parent = < 1 >;

Programming Note

Most device trees in Device Tree Syntax (DTS) (see Appendix A) will not contain explicit phandle properties. The DTC tool automatically inserts the phandle properties when the DTS is compiled into the binary DTB format.

explain some more
The ePAPR explains phandles a bit more in Appendix A ("Device Tree Source Format") and shows more context of phandle usage in Appendix B1 (Ebony Device Tree) and Appendix B2 (MPC8572DS Device Tree).

Let's step back and ask what is the reason for having a phandle? It is really just a hack to get around the fact that device tree does not have a pointer data type. It is a way to reference "that node over there that is related to this node for some reason". In the above example from the ePAPR, it is a way to specify what node is the interrupt controller for a device node.

Modifying the example to show the use of the phandle helps a little bit:

pic@10000000 { phandle = < 1 >; };

A phandle value of 1 is defined. Another device node could reference the pic node with a  phandle value of 1:

uart@20000000 { interrupt-parent = < 1 >; };

There is nothing magic about the value '1'. You are free to use any value that you desire, as long as you do not specify the same value for the phandle property in two different nodes.

But you are not likely to find a modern device tree source file that explicitly defines a phandle or specifies a u32 value when referencing a phandle. This is because the dtc compiler kindly creates phandles from labels. So the above example would look like:

PIC_3: pic@10000000 { interrupt-controller; };

uart@20000000 { interrupt-parent = < &PIC_3 >; };

The '&' tells dtc that the following string is a phandle referencing the label matching the string.

dtc will create a unique u32 value for each label that is used for a phandle reference. If you insist on defining a phandle property in one node, and specify a label on a different node's name, then dtc will be aware of any phandle values explicitly stated and will not use those values when creating phandle values for labeled nodes.

The phandle reference can refer to a label that occurs later in the source file.

If you do not want to use a label you can instead specify a full path to reference a phandle. In this example, both uart@20000000 and uart@30000000 are pointing to the same interrupt controller node:

/{     soc { PIC_3: pic@10000000 { interrupt-controller; };     };

uart@20000000 { interrupt-parent = < &PIC_3 >; };

uart@30000000 { interrupt-parent = < &{/soc/pic@10000000} >; }; };

The previous example may lead to another question from the astute reader. Can a phandle reference by path occur when the target node does not have a label? The dtc compiler generates the phandle property because there is a phandle reference, not because the node has a label. So the answer is yes, as seen in the next example:

/{     soc { pic@10000000 { interrupt-controller; };     };

uart@30000000 { interrupt-parent = < &{/soc/pic@10000000} >; }; };

NOTE 1: A '&' only refers to a phandle if it is inside an array. If outside an array, it refers to a path. See Labels for more information.

NOTE 2: One place you will see phandles defined and a u32 value used for a phandle reference is if you decompile a compiled device tree, aka a .dtb or device tree blob. This is because labels are not retained in the compiled device tree. You will see that dtc simply allocates a unique u32 value for each label that is referenced and replaces any reference to the label with the unique u32 value.

kernel usage
As mentioned in the above example, all knowledge of label names and whether a value in a property is a phandle is lost when the source is compiled. You can see this by compiling a simple example into a device tree blob and then decompiling the blob:

$ cat test_phandle.dts

/dts-v1/;

/ {       #address-cells = ; #size-cells = ; soc { #address-cells = ; #size-cells = ;

pic_3: pic@100 { reg = ; interrupt-controller; };       };

uart@200 { reg = ; interrupt-parent = < &pic_3 >; }; };

$ dtc -O dtb test_phandle.dts >test_phandle.dtb $ dtc -O dts test_phandle.dtb /dts-v1/;

/ {	#address-cells = ; #size-cells = ;

soc { #address-cells = ; #size-cells = ;

pic@100 { reg = ; interrupt-controller; linux,phandle = ; phandle = ; };	};

uart@200 { reg = ; interrupt-parent = ; }; };

Thus the value of the property "interrupt-parent" in node uart@200 is merely a u32 value. It is not a pointer to the location of node /soc/pic@100 in the device tree blob. When loaded by the kernel, it is also not a pointer in the expanded device tree. It is merely a value in a property. The only way that kernel code knows that the value in the "interrupt-parent" property is a phandle is because the binding documentation has defined that the value is a phandle. Thus the code that reads the "interrupt-parent" property has to be written to treat that value as a phandle. When the code needs to find what node the phandle points to, it calls of_find_node_by_phandle, which searches for a node containing a "phandle" property containing the specified value.

One other oddity you may have noted in the above example is that dtc created two properties for the label, "phandle" and "linux,phandle". Both of these properties will always have the same value in a given node. Do not use "linux,phandle" - this is a deprecated property that dtc continues to generate to maintain compatibility.

illegal values
The values 0 and -1 (0xffffffff) are illegal phandle values.

dtc will report these as a "bad value":

ERROR (explicit_phandles): /soc/node_0 has bad value (0x0) in phandle property ERROR (explicit_phandles): /soc/node_ffffffff has bad value (0xffffffff) in phandle property

Labels
In an array a reference to a label will be expanded to that node's phandle. For instance, the property interrupt-parent in the following example.

Outside an array, a reference to a label will be expanded to that node's full path. For instance, the property interrupt-parent-path in the following example.

$ cat example_label_a.dts

/dts-v1/;

/ {       soc { #address-cells = ; #size-cells = ;

pic_3: pic@100 { reg = ; interrupt-controller; };

uart { interrupt-parent = < &pic_3 >; interrupt-parent-path = &pic_3 ; };       };

}; $ dtc -O dts example_label_a.dts /dts-v1/;

/ {

soc { #address-cells = ; #size-cells = ;

pic_3: pic@100 { reg = ; interrupt-controller; linux,phandle = ; phandle = ; };

uart { interrupt-parent = ; interrupt-parent-path = "/soc/pic@100"; };	}; };

Outside an array, a reference to a label will be expanded to that node's full path. The previous example shows how this value can be used as a property value. The following example shows how that can be used as the full path of a node.

Using a label for a node's path is commonly used to refer to a previously existing node for the purpose of modifying the value of one or more properties in that node. In this example, the reg property is modified. $ cat example_label_b.dts

/dts-v1/;

/ {       soc { #address-cells = ; #size-cells = ;

pic_3: pic@100 { reg = ; interrupt-controller; };

};

};

&pic_3 { reg = ; }; $ dtc -O dts example_label_b.dts /dts-v1/;

/ {

soc { #address-cells = ; #size-cells = ;

pic_3: pic@100 { reg = ; interrupt-controller; };	}; };

Labels on a property or a property value
Labels may also appear before or after any component of a property value, or between elements of an array, or between bytes of a bytestring. e.g. reg = reglabel: <0 sizelabel: 0x1000000>; e.g. prop = [ab cd ef byte4: 00 ff fe]; e.g. str = start: "string value" end: ;

There is no syntax available to reference data labels elsewhere in dts source. There is no additional information added to the flattened device tree (.dtb) file for data labels.

The only use of data labels is when -Oasm is specified. In this case, the labels are exposed in the assembly output file. The intent is that the compiled assembly file would be linked into a very minimalist boot loader. This would allow the boot loader to easily perform very simple property data changes (in-place alterations, no re-sizing) without the complexity of FDT parsing.

Labels on memreserve
Labels may also appear on /memreserve/. e.g. my_memreserve: /memreserve/   0x0000000000000000 0x0000000000001000; e.g. my_memreserve: my_memreserve_v2: /memreserve/   0x0000000000000000 0x0000000000001000;

There is no syntax available to reference memreserve labels elsewhere in dts source. There is no additional information added to the flattened device tree (.dtb) file for data labels.

The only use of memreserve labels is when -Oasm is specified. In this case, the labels are exposed in the assembly output file. The intent is that the compiled assembly file would be linked into a very minimalist boot loader. This would allow the boot loader to easily perform very simple property data changes (in-place alterations, no re-sizing) without the complexity of FDT parsing.

Label as a phandle vs Label as a path
The description of Labels  example_label_a.dts showed that a label used in a property value could expand either to the phandle value of the referenced node (see property "interrupt-parent") or a string containing the path of the reference node (see property "interrupt-parent-path").

It is more common to use the phandle value form because:
 * less space is used in the Flattened Device Tree
 * it is easier to parse a multi-element property if the node reference is a fixed size phandle instead of a variable length string
 * it is easier and more clear to specify a multi-element property that consists of 32 bit items than one that consists of a mix of 32 bit items and a string (see the values of properties "interrupt-parent" and "interrupt-parent-path" in example_label_c.dts below)

$ cat example_label_c.dts

/dts-v1/;

/ {       soc { #address-cells = ; #size-cells = ;

pic_3: pic@100 { reg = ; interrupt-controller; };

uart { // NOTE: this is not a valid interrupt-parent binding interrupt-parent = < 7 &pic_3 4 >; interrupt-parent-path = < 7 >, &pic_3, < 4 > ; };       };

}; $ dtc -O dts example_label_c.dts /dts-v1/;

/ {

soc { #address-cells = ; #size-cells = ;

pic_3: pic@100 { reg = ; interrupt-controller; linux,phandle = ; phandle = ; };

uart { interrupt-parent = ; interrupt-parent-path = [00 00 00 07 2f 73 6f 63 2f 70 69 63 40 31 30 30 00 00 00 00 04]; };	}; };

Label vs aliases node property
A label can be used in a device tree source file as either a phandle value or a path, depending on context, as seen in sections Labels and Label as a phandle vs Label as a path.

The "/aliases" node contains properties that are aliases. The name of each property is the name of the alias, and the value of the property is the full path to a node in the device tree.

The aliases are not used directly in the device tree source, but are instead dereferenced by the Linux kernel. When a path is provided to of_find_node_by_path or of_find_node_opts_by_path, if the path does not begin with a "/" then the first element of the path must be a property name in the "/aliases" node. That element is replaced with the full path from the alias.

#xxx-cells property name
Property names with a leading '#', ending with '-cells' are used to provide information about the format of another property. The convention is that the #xxx-cells property describes the number of u32 cells used to hold the data item in a property named 'xxxs'.

A common pattern for the 'xxxs' property is to contain tuples of the form:

phandle cell_1 cell_2 ... cell_n where: #xxx-cells determines 'n'   if n is zero, typically the tuple contains just phandle

Exceptions to the rules are noted in the following table.

'#' prefixed property names in Linux 4.7-rc2 documented bindings Entries with no corresponding property name are because this table is still under construction. '#xxx-cells' name                corresponding property name -                --                                   dma-ranges                            -- exception to naming, phandle form node: first tuple element child node: second tuple element ranges                               -- exception to naming, phandle form node: first tuple element child node: second tuple element #qca,ddr-wb-channel-cells dma-ranges, third tuple element      -- exception to naming, phandle form ranges, third tuple element          -- exception to naming, phandle form
 * 1) address-cells                   reg, first tuple element              -- exception to naming, phandle form
 * 1) atmel,pll-clk-output-range-cells
 * 2) atmel,pll-output-range-cells
 * 3) clock-cells                     clocks, second tuple element
 * 4) cooling-cells                   cooling device, second tuple element
 * 5) dma-cells                       dmas, second tuple element
 * 6) gpio-cells                      gpios
 * 7) gpio-range-cells
 * 8) hwlock-cells
 * 9) interrupt-cells                 interrupts                            -- exception to phandle form
 * 10) interrupt-cells                 interrupt-map                         -- exception to naming
 * 11) interrupt-cells                 interrupts-extended                   -- exception to naming
 * 12) io-channel-cells                io-channels, second tuple element
 * 13) iommu-cells
 * 14) mbox-cells
 * 15) msi-cells
 * 16) nvidia,mipi-calibrate-cells
 * 17) phy-cells                       phys
 * 18) phys-cells
 * 19) pinctrl-single,gpio-range-cells
 * 20) power-domain-cells
 * 21) pwm-cells                       pwms
 * 1) qcom,state-cells
 * 2) rcpm-wakeup-cells
 * 3) reset-cells
 * 4) size-cells                      reg, second tuple element             -- exception to naming, phandle form
 * 1) sleep-cells
 * 2) sound-dai-cells                 sound-dai                             -- exception to naming
 * 3) stream-id-cells
 * 4) thermal-sensor-cells            thermal-sensors, second tuple element

The '#xxx-cells' properties may or may not be inheritable from an ancestor node, or from a node found via phandle search. This can be determined from the binding documentation.

Some examples of how #xxx-cells is used follow.

Example 1 is a simple interrupt setup. A uart device specifies an interrupt with a tuple size of 1. The size of the tuples in the "interrupts" property is found in the "#interrupt-cells" property that is in the interupt controller node, according to the binding document Documentation/devicetree/bindings/interrupt-controller/interrupts.txt. In this case, the interrupt controller is the node referenced the the phandle contained in property "interrupt-parent".

Note that the "interrupt" property does not follow the common tuple form of:

phandle cell_1 cell_2 ... cell_n

An example that includes phandle in a tuple can be seen in the "interrupts-extended" property in example 3.1.

Example 1 INTC_1: intc@10000000 { reg = ; interrupt-controller; #interrupt-cells = <1>; };       uart@20000000 { compatible = "my-uart-type"; reg = ; interrupt-parent = <&INTC_1>; interrupts = <17>; };

In example 2, the tuple size remains 1, but the uart device uses two interrupts. An example of a second interrupt might be for an alarm interrupt to wake the system when the uart detects input.

Example 2 INTC_1: intc@10000000 { reg = ; interrupt-controller; #interrupt-cells = <1>; };       uart@20000000 { compatible = "my-uart-type"; reg = ; interrupt-parent = <&INTC_1>; interrupts = ; };

In example 3, the tuple size is changed from 1 to 2, and the uart device uses one interrupt. The second value in the tuple is a flag (see interrupts.txt). The value of the "interrupts" property is exactly the same as in the previous example, but has an entirely different meaning. The meaning is defined by the binding document for the specific interrupt controller. In the previous example, " " specified interrupt 17 and interrupt 4. In this example it specifies interrupt 17 with a flag value of 4 (meaning active high level-sensitive according to interrupts.txt.


 * How do I know what value to specify for property "#interrupt-cells" in the interrupt controller?
 * The binding document for the specific type of interrupt controller will specify this value.
 * How do I know the semantics of each element of the tuple?
 * The binding document for the specific type of interrupt controller will specify the tuple semantics.
 * How do I know which binding document applies to the interrupt controller when adding a device node to a device tree that contains an interrupt controller?
 * To keep the examples less cluttered, a key property has been left out. The interrupt controller nodes must contain a "compatible" property that defines the specific programming model for the device.  The binding document that specifies a "compatible" property value that matches the value in the interrupt controller node is the applicable document.

Example 3 INTC_1: intc@10000000 { reg = ; interrupt-controller; #interrupt-cells = <1>; };       uart@20000000 { compatible = "my-uart-type"; reg = ; interrupt-parent = <&INTC_1>; interrupts = ; };

The dtc compiler has syntax that allows specifying tuple values in a way that distinguishes between two tuples with one element per tuple and one tuple with two elements per tuple. The difference between the tuple format in example 2 and example 3 would be more clear if this syntax was used:

Example 3.1 Two tuples, one element per tuple: interrupts = <17>, <4>; One tuple, two elements per tuple: interrupts = ; Three tuples, with formats of: 1) phandle, interrupt   2) phandle, interrupt, flags 2) phandle, interrupt   interrupts-extended = < &INTC_1 17 >, < &INTC_2 23 8 >, < &INTC_4 27 >; There are no type declarations for arrays and tuples, so the dtc compiler can not enforce conformance with tuple size in the value declarations. Thus the above three tuples would properly compile if specified as:    interrupts-extended = < &INTC_1 17 &INTC_2 >,, < &INTC_4 27 >; even though it appears not to match the formats of the three tuples. If you compile a device tree source file containing each of the two above definitions of interrupts, then decompile the resulting .dtb file, you will see the dtc simply converts both forms to be:    <0x2 0x11 0x3 0x17 0x8 0x4 0x1b> (In the test .dts file I created, &INTC_1 has the value 0x2, &INTC_2 has the value 0x3, and &INTC_4 has the value 0x4.)

PCI Host Bridge
See PCI Host Bridge for information about PCI host bridges and PCI address translation.

Interrupt Nexus
An Interrupt Nexus is jargon for a device tree node that contains an interrupt-map property.

See Interrupt Mapping immediately below.

Interrupt Mapping
A bus controller routes interrupts from devices on the bus to an interrupt controller available to the bus controller. The interrupt map provides the correspondance between interrupts on the bus and where the bus controller routes those interrupts.

See Advanced Interrupt Mapping for information about complex interrupt mapping. The example is for PCI, but the concepts also apply to non-PCI nodes.

Some useful reference information when reading Advanced Interrupt Mapping is located in section "2.4.3 Interrupt Nexus Properties" of the ePAPR.

#include vs. /include/
There are two directives available to incorporate an external file into a devicetree source file:
 * #include FILE
 * /include/ FILE

The Linux compile process for devicetree source file XXX.dts is:

XXX.dts (file) --> cpp (tool) --> XXX.dts.tmp (file) --> dtc (tool) --> XXX.dtb (file)


 * 1) include is processed by cpp

/include/ is processed by dtc

All files incorporated via #include appear within file XXX.dts.tmp.

A file incorporated via /include/ may not contain #include because the file is not subsequently processed by cpp after being processed by dtc.

Thus
 * a file incorporated via #include may contain #include and/or /include/
 * a file incorporated via /include/ may contain /include/

error messages
Error messages can be cryptic.

Error: xxx.dts:1.1-2 syntax error Is reporting that something is not valid in file xxx.dts line 1 columns 1-2

defaults and inheritance of #address-cells and #size-cells
See: Device Tree Linux: defaults and inheritance of #address-cells and #size-cells

/firmware node
See: Device Tree Linux: (/chosen node vs /firmware node