Device Tree Mysteries

From eLinux.org
Revision as of 17:43, 24 March 2017 by Frowand (talk | contribs) (Common Linux Driver Errors: initial content)
Jump to: navigation, search


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 devicetree: Kernel Internals and Practical Troubleshooting [PDF] , ELC Europe 2014 by Frank Rowand.

Common Linux Driver Errors

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 = <2147483647>;
                b = <2147483648>;
                c = <2147483649>;
                d = <2147483650>;
        };

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]

Device Tree source

Signed Property Values

ePAPR Version 1.1 lists the following data types for properties:

<empty>
<u32>
<u64>
<string>
<prop-encoded-array>
<phandle>
<stringlist>

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 of_property_read_s32().

Phandle

cryptic

The ePAPR tells us

2.3.3 phandle

Property: phandle
Value type: <u32>
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 = < 0x1 >;
	#size-cells = <0x1>;
        soc {
        	#address-cells = < 0x1 >;
		#size-cells = <0x1>;

                pic_3: pic@100 {
		        reg = < 0x100 0x20 >;
                        interrupt-controller;
                };
        };

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

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

/ {
	#address-cells = <0x1>;
	#size-cells = <0x1>;

	soc {
		#address-cells = <0x1>;
		#size-cells = <0x1>;

		pic@100 {
			reg = <0x100 0x20>;
			interrupt-controller;
			linux,phandle = <0x1>;
			phandle = <0x1>;
		};
	};

	uart@200 {
		reg = <0x200 0x10>;
		interrupt-parent = <0x1>;
	};
};

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 = < 0x1 >;
		#size-cells = < 0x1 >;

                pic_3: pic@100 {
			reg = < 0x100 0x20 >;
                        interrupt-controller;
                };

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

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

/ {

	soc {
		#address-cells = <0x1>;
		#size-cells = <0x1>;

		pic_3: pic@100 {
			reg = <0x100 0x20>;
			interrupt-controller;
			linux,phandle = <0x1>;
			phandle = <0x1>;
		};

		uart {
			interrupt-parent = <0x1>;
			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 = < 0x1 >;
		#size-cells = < 0x1 >;

                pic_3: pic@100 {
			reg = <0x100 0x20 >;
                        interrupt-controller;
                };

        };

};

&pic_3 {
	reg = <0x200 0x30 >;
};
$ dtc -O dts example_label_b.dts 
/dts-v1/;

/ {

	soc {
		#address-cells = <0x1>;
		#size-cells = <0x1>;

		pic_3: pic@100 {
			reg = <0x200 0x30>;
			interrupt-controller;
		};
	};
};

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 labels (as of dtc version 1.4.2) 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 = < 0x1 >;
		#size-cells = < 0x1 >;

                pic_3: pic@100 {
			reg = < 0x100 0x20 >;
                        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 = <0x1>;
		#size-cells = <0x1>;

		pic_3: pic@100 {
			reg = <0x100 0x20>;
			interrupt-controller;
			linux,phandle = <0x1>;
			phandle = <0x1>;
		};

		uart {
			interrupt-parent = <0x7 0x1 0x4>;
			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
-----------------                 ------------------------------------------
#address-cells                    reg, first tuple element -- exception to naming, phandle form
#atmel,pll-clk-output-range-cells
#atmel,pll-output-range-cells
#clock-cells                      clocks, second tuple element
#cooling-cells                    cooling device, second tuple element
#dma-cells                        dmas, second tuple element
#gpio-cells                       gpios
#gpio-range-cells
#hwlock-cells
#interrupt-cells                  interrupts -- exception to phandle form
#interrupt-cells                  interrupt-map -- exception to naming
#interrupt-cells                  interrupts-extended -- exception to naming
#io-channel-cells                 io-channels, second tuple element
#iommu-cells
#mbox-cells
#msi-cells
#nvidia,mipi-calibrate-cells
#phy-cells                        phys
#phys-cells
#pinctrl-single,gpio-range-cells
#power-domain-cells
#pwm-cells                        pwms
#qca,ddr-wb-channel-cells
#qcom,state-cells
#rcpm-wakeup-cells
#reset-cells
#size-cells                       reg, second tuple element -- exception to naming, phandle form
#sleep-cells
#sound-dai-cells                  sound-dai  -- exception to naming
#stream-id-cells
#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 = <0x10000000 0x1000>;
               interrupt-controller;
               #interrupt-cells = <1>;
       };

       uart@20000000 {
               compatible = "my-uart-type";
               reg = <0x20000000 0x1000>;
               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 = <0x10000000 0x1000>;
               interrupt-controller;
               #interrupt-cells = <1>;
       };

       uart@20000000 {
               compatible = "my-uart-type";
               reg = <0x20000000 0x1000>;
               interrupt-parent = <&INTC_1>;
               interrupts = <17 4>;
       };

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, "<17 4>" 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 = <0x10000000 0x1000>;
               interrupt-controller;
               #interrupt-cells = <1>;
       };

       uart@20000000 {
               compatible = "my-uart-type";
               reg = <0x20000000 0x1000>;
               interrupt-parent = <&INTC_1>;
               interrupts = <17 4>;
       };

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 = <17 4>;

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 >, < 23 8 >, < &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.

dtc device tree compiler

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