Difference between revisions of "Device Tree Linux"

From eLinux.org
Jump to: navigation, search
(chosen node: initial contents)
(chosen node: change Linux behaviour from bug)
Line 226: Line 226:
---  Linux
---  Linux
   The chosen node is required. This is a bug.
   The chosen node is required.
  The bug is reported in http://www.spinics.net/lists/arm-kernel/msg549589.html
      From: Fabio Estevam <fabio.estevam@nxp.com>
      Subject: [PATCH] ARM: dts: imx: Pass an empty 'chosen' node
      Date: Mon, 19 Dec 2016 13:28:18 -0200
      Commit 7f107887d199 ("ARM: dts: imx: Remove skeleton.dtsi") causes boot
      issues when the bootloader does not create a 'chosen' node if such node
      is not present in the dtb.
      The reason for the boot failure is well explained by Javier Martinez
      Canillas: "the decompressor relies on a pre-existing chosen node to be
      available to insert the command line and merge other ATAGS info."
      , so pass an empty 'chosen' node to fix the boot problem.
      This issue has been seen in the kernelci reports with Barebox as
      Fixes: 7f107887d199 ("ARM: dts: imx: Remove skeleton.dtsi")
  A workaround (adding the chosen node back to .dts files not containing
  one) was accepted in https://www.spinics.net/lists/arm-kernel/msg557466.html

Revision as of 18:58, 25 January 2017

Top Device Tree page

Device Tree Framework Source Code

The device tree framework source code is located in drivers/of/.

Code for manipulating the flattened device tree (FDT) is is scripts/dtc/libfdt.

libfdt is imported from the external project maintained in

Linux Man pages

Linux man pages are a work in progress.

The current version of the pages can be downloaded or built locally.

Compiling dts source file

This is an example of compiling arch/arm/boot/dts/qcom-msm8960-cdp.dts

The make target is the name of the .dts file, with ".dts" changed to ".dtb".

  • Check that the config option that enables the dtb is set
  dtb-$(CONFIG_ARCH_QCOM) += \
         qcom-msm8960-cdp.dtb \

$ grep CONFIG_ARCH_QCOM .config
  • specify the correct architecture in the make command (or export the ARCH)
export ARCH="arm"
make qcom-msm8960-cdp.dtb
ARCH="arm" make qcom-msm8960-cdp.dtb

Linux Gotchas

node name case sensitivity

Node names are supposed to be case sensitive. The function that checks whether a node name matches a string may be defined by an architecture or may be the generic implementation. Due to some issues with old Macs the generic implementation was case insensitive. There is an architecture defined version that is not case sensitive.

Expect this to change so that the generic node name compare function is case sensitive, and only a few select sub-architectures will not be case sensitive.

disabled nodes

Linux has widespread use of the "status" property to indicate that a node does not exist. This is used to create a generic .dtsi file that defines all of the potential components of a device which might contain many different functions. When the device is used in a system, many of the functions might not be routed to connectors or might not be usable due to needing pins that are multiplexed with other devices that are active. The convention is to set the "status" property of such functions to "disabled" in the .dtsi file, then the system .dts file that includes the .dtsi will change the "status" property of functions that should be enabled to "ok".

Some kernel code does not check the node "status" property before trying to configure, probe, or enable it.

Expect efforts to fix the kernel code to respect the "status" property.

Linux conventions

  • hex constants are lower case
    • use "0x" instead of "0X"
    • use a..f instead of A..F, eg 0xf instead of 0xF
  • node names
    • use "-" instead of "_"
    • unit-address does not have a leading "0x" (the number is assumed to be hexadecimal)
    • unit-address does not have a leading zeros
    • should begin with a character in the range 'a' to 'z', 'A' to 'Z'
  • property names
    • should be lower case
    • should begin with a character in the range 'a' to 'z'
  • maximum depth of device tree
    • #define FDT_MAX_DEPTH 64

Linux Preferences

Items in this section may be less firm or certain than items in "Linux Conventions".

If you can document or explain why any item should move to "Linux Conventions" please email frowand.list at gmail.com".


The Linux kernel build system preprocesses dts files with cpp before passing them to dtc. The dtc compileralso has an "/include/" directive.

  • Files that are included via the "/include/" directive can not contain any cpp directives. This is because such files are not visible to cpp.
  • Although cpp can do conditional inclusion with features such as "#if" and "#ifdef" this is frowned upon.
  • Common use of cpp is for "#include" and simple "#defines" for symbolic names.
  • Bindings related include files are in include/dt-bindings/
  • More complex macros do exist, but are rare.
Complex example 1

#define OMAP_IOPAD_OFFSET(pa, offset)   (((pa) & 0xffff) - (offset))

#define OMAP2420_CORE_IOPAD(pa, val)    OMAP_IOPAD_OFFSET((pa), 0x0030) (val)
Complex example 2


#define MATRIX_KEY(row, col, code)      \
        ((((row) & 0xFF) << 24) | (((col) & 0xFF) << 16) | ((code) & 0xFFFF))

interrupts vs interrupts-extended

Should I use 1) the "interrupts" property in association with the "interrupt-parent" property or 2) the "interrupts-extended" property?

"Interrupts" is well understood and commonly used. It is ok to use that model.

The main purpose of "interrupts-extended" is to allow one device to have multiple interrupts that are handled by different controllers, without introducing a (more complex) "interrupt-map" property in the parent.

Linux vs ePAPR Version 1.1

#address-cells and #size-cells

---  ePAPR

   2.3.5 #address-cells and #size-cells
      'The #address-cells and #size-cells properties are not
       inherited from ancestors in the device tree. They shall be
       explicitly defined.'

---  Linux

   #address-cells defaults to 2
   #size-cells defaults to 1
   dtc may warn that the default is being used.

aliases node

---  ePAPR

   3.3 aliases node
      'A client program may use an alias property name to refer to
       a full device path as all or part of its string value.'

      'A client program, when considering a string as a device path,
       shall detect and use the alias.'

---  Linux

   of_find_node_by_path() and of_find_node_opts_by_path() check
   whether the path begins with "/".  If it does not, then the first
   element must be a property in the aliases node.  That first element
   is replaced with the value of the property in the aliases node.

   It is not known whether other code (such as drivers) is aware of
   the requirement to be aware of aliases.

   Linux also has a concept of numeric id derived from the property
   names in the aliases node.  All trailing digits in the property
   name are used to create the "id".  The "stem" is the property
   name, with the trailing digits removed.  For each property in
   the aliases node, the tuple of stem, id, and the device tree
   node pointer for the path in the property's value is added to
   the aliases_lookup list.  A driver can use of_alias_get_id()
   to retrieve the id for a given stem and device tree node

   This is commonly used to number devices, although the practice
   is controversial.

chosen node

---  ePAPR

   3.5 chosen node
   The chosen node is not required.  If it was required, sections 3.1 and 3.5
   would explicitly state such (for example, section 3.6 CPUS Node Properties
   states 'A cpus node is required for all device trees.').

   The list of required nodes is listed in section 3.1:

   3.1 Base Device Node Types

      'The sections that follow specify the requirements for the base set of device nodes required in an
       ePAPR-compliant device tree.

       All device trees shall have a root node and the following nodes shall be present at the root of all
       device trees:
          • One cpus node
          • At least one memory node'

---  Linux

   The chosen node is required.

device_type property

---  ePAPR

   2.3.11 device_type
      'The device_type property was used in IEEE 1275 to describe the device’s FCode
       programming model. Because ePAPR does not have FCode, new use of the property is
       deprecated, and it should be included only on cpu and memory nodes for compatibility with
       IEEE 1275–derived device trees.'

---  Linux

   Many Linux bindings have a device_type property.  Many of these bindings are not
   well documented.

   Linux source code accesses this property via for_each_node_by_type(),
   of_find_node_by_type(), and by open coding.  As of 4.10-rc3, the list
   of values searched for by for_each_node_by_type() and of_find_node_by_type()



---  ePAPR

   Appendix A Device Tree Source Format (version 1)

   Node and property definitions

      'Device tree nodes are defined with a node name and unit address with braces marking the start and
       end of the node definition. They may be preceded by a label.'

   There is no note as to whether a label is allowed on the root node.

---  Linux

   dtc does not allow a label on the root node.


Node names

---  ePAPR

   2.2.1 Node Names
      The node name follows the convention:
      Characters in node-name may be:

---  Linux

   dtc allows characters in node-name to be:


Property names

---  ePAPR Property Names
      Characters in the property name may be:

---  Linux

   dtc allows characters in property name to be:

      # is only recommended as the first character of a property name

Label names

---  ePAPR

   No information on characters in label names.
---  Linux

   dtc allows characters in label name to be:
   The label name may not begin with 0-9

status property

---  ePAPR

   2.3.4 status
      'Valid values for status are: "okay", "disabled", "fail", "fail-sss".
       "Refer to the device binding for details on what disabled means for
       a given device.'

   3.7.1 General Properties of CPU nodes
      Valid values for status are: "okay", "disabled".

---  Linux

   A node is enabled if:
      status == "ok"
      status == "okay"
      status property does not exist
   Convention for disabling a node:
      status == "disabled"
   Not all code checks whether a node is disabled.  These cases are bugs.

"ABI" stability

Are device tree bindings stable?

Well.... Let me put this open jar full of gasoline on the floor and step away for a little while. Oh, can I loan you a lighter or a book of matches?

  • Email thread: DT bindings as ABI [was: Do we have people interested in device tree janitoring / cleanup?]

Bindings review process

devicetree/bindings/submitting-patches.txt was created following discussion at the 2013 Kernel Summit.

Email thread: [Ksummit-2013-discuss] [ATTEND] Handling of devicetree bindings

The slides that Grant Likely presented at the Kernel Summit discussion were in an email attachment that the mail list stripped. Here are the slides: It's Broken! Fixing the DT binding process (PDF)

Slides 18 and 19 of [PDF] "Device Tree, the Disaster so Far", ELC Europe 2013 by Mark Rutland.

Support of different hardware versions in a single driver

Examples of drivers that match more than one compatible string.

This list is not an endorsement of any particular technique. It is instead a (partial) list of some existing code in the Linux kernel.

The examples are not meant to capture each method entirely; they are instead meant to illustrate the basic concept.

Hardware Version in struct of_device_id.data

The hardware version is used throughout the driver to choose alternate actions.


static const struct of_device_id arm_smmu_of_match[] = {
        { .compatible = "arm,smmu-v1", .data = (void *)ARM_SMMU_V1 },
        { .compatible = "arm,smmu-v2", .data = (void *)ARM_SMMU_V2 },
        { .compatible = "arm,mmu-400", .data = (void *)ARM_SMMU_V1 },
        { .compatible = "arm,mmu-401", .data = (void *)ARM_SMMU_V1 },
        { .compatible = "arm,mmu-500", .data = (void *)ARM_SMMU_V2 },
        { },
MODULE_DEVICE_TABLE(of, arm_smmu_of_match);

static int arm_smmu_device_dt_probe(struct platform_device *pdev)
        const struct of_device_id *of_id;

        of_id = of_match_node(arm_smmu_of_match, dev->of_node);
        smmu->version = (enum arm_smmu_arch_version)of_id->data;


        if (smmu->version > ARM_SMMU_V1) {

static struct platform_driver arm_smmu_driver = {
       .driver = {
                .name           = "arm-smmu",
                .of_match_table = of_match_ptr(arm_smmu_of_match),
        .probe  = arm_smmu_device_dt_probe,
        .remove = arm_smmu_device_remove,

Function Call Table pointer in struct of_device_id.data

The function call table is used throughout the driver to choose alternate actions.


static const struct xadc_ops xadc_zynq_ops = {
        .read = xadc_zynq_read_adc_reg,
        .write = xadc_zynq_write_adc_reg,
        .setup = xadc_zynq_setup,
        .get_dclk_rate = xadc_zynq_get_dclk_rate,
        .interrupt_handler = xadc_zynq_interrupt_handler,
        .threaded_interrupt_handler = xadc_zynq_threaded_interrupt_handler,
        .update_alarm = xadc_zynq_update_alarm,

static const struct of_device_id xadc_of_match_table[] = {
        { .compatible = "xlnx,zynq-xadc-1.00.a", (void *)&xadc_zynq_ops },
        { .compatible = "xlnx,axi-xadc-1.00.a", (void *)&xadc_axi_ops },
        { },
MODULE_DEVICE_TABLE(of, xadc_of_match_table);

static int xadc_probe(struct platform_device *pdev)
        const struct of_device_id *id;
        id = of_match_node(xadc_of_match_table, pdev->dev.of_node);
        indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*xadc));
        xadc = iio_priv(indio_dev);
        xadc->ops = id->data;
        ret = xadc->ops->setup(pdev, indio_dev, irq);

static struct platform_driver xadc_driver = {
        .probe = xadc_probe,
        .remove = xadc_remove,
        .driver = {
                .name = "xadc",
                .of_match_table = xadc_of_match_table,

Hardware Description pointer in struct of_device_id.data

The hardware description data is used to configure the device.

This struct pointed to by struct of_device_id.data in this example includes a function call table in addition to the hardware description fields.


static const struct twl6030_gpadc_platform_data twl6030_pdata = {
        .iio_channels = twl6030_gpadc_iio_channels,
        .nchannels = TWL6030_GPADC_USED_CHANNELS,
        .ideal = twl6030_ideal,
        .start_conversion = twl6030_start_conversion,
        .channel_to_reg = twl6030_channel_to_reg,
        .calibrate = twl6030_calibration,

static const struct of_device_id of_twl6030_match_tbl[] = {
                .compatible = "ti,twl6030-gpadc",
                .data = &twl6030_pdata,
                .compatible = "ti,twl6032-gpadc",
                .data = &twl6032_pdata,
        { /* end */ }

static int twl6030_gpadc_probe(struct platform_device *pdev)
        const struct of_device_id *match;
        const struct twl6030_gpadc_platform_data *pdata;

        match = of_match_device(of_twl6030_match_tbl, dev);
        pdata = match->data;
        indio_dev = devm_iio_device_alloc(dev, sizeof(*gpadc));
        gpadc = iio_priv(indio_dev);
        gpadc->pdata = pdata;
        platform_set_drvdata(pdev, indio_dev);
        ret = pdata->calibrate(gpadc);
        indio_dev->channels = pdata->iio_channels;
        indio_dev->num_channels = pdata->nchannels;