Devicetree: Difference between revisions

From Mainlining Wiki
Jump to navigation Jump to search
Knuxify (talk | contribs)
mNo edit summary
Knuxify (talk | contribs)
 
(9 intermediate revisions by the same user not shown)
Line 1: Line 1:
The '''devicetree''' (device tree, DT (DTS/DTB)) is a data structure which holds information about all components present on a device. This data is structured in nested nodes with key/value property pairs for configuration.
{{Navbox devicetree}}
The '''devicetree''' (device tree, DT) is a tree structure that describes the hardware register layout and configuration of a device. In the Linux kernel, as well as in other DT-using projects like U-Boot, it is the primary method of discovering peripherals on embedded platforms such as ARM.


In simpler terms - a devicetree tells the kernel (or another DT-compatible piece of software/firmware like a bootloader) where each component is in register space/on an I2C or similar bus, and what settings to use to set it up. It is the basic mechanism for discovering components on embedded platforms, including ARM.
Devicetrees are written in a plaintext format known as the '''Device Tree Source (DTS)''' format. The DTS is later compiled into a '''Device Tree Blob (DTB)'''; in this form, it can be loaded by software/firmware.
 
Devicetrees are validated using '''devicetree schema'''; this schema specifies allowed properties for nodes based on their <code>compatible</code> string. Devicetree schema is defined through '''bindings''', YAML files containing schema information (older bindings use TXT format, but this is deprecated). Bindings for most Linux components can be found in <code>Documentation/devicetree/bindings</code>; there is also a [https://github.com/devicetree-org/dt-schema core DT schema] defining the most basic components and syntax.
 
== History ==
 
The initial version of the devicetree standard was developed as part of the OpenFirmware initiative; from this standard, the Flattened Device Tree (FDT) emerged and was adopted by the Linux kernel for PowerPC platforms. Around 2009, discussions began to include FDT support for ARM[1]. It was eventually added and first device trees began to appear in 2011[2], although the format didn't see wider usage (especially in vendor kernels) until around 2013/2014.


Nowadays, the devicetree standard is managed by [https://www.devicetree.org/ devicetree.org]; they maintain the latest version of the [https://www.devicetree.org/specifications Devicetree Specification] and the related set of [https://github.com/devicetree-org/dt-schema core DT schema].
Devicetrees are validated using '''devicetree schema''', which is described in '''DT bindings'''; see [[/Bindings]] for more information.


Before the introduction of devicetrees, ARM kernels used '''board files'''. These were C files stored in <code>arch/arm/mach-*</code> which served a similar purpose to devicetrees - they contained structures for defining component configuration ("platform data"). Unlike device trees however, they could also define C functions, since they were regular C sources compiled into the kernel. Board files technically still exist (citation needed?), but are no longer in wide use.
== Introduction ==


== Device Tree Source (DTS) and Device Tree Blob (DTB) ==
An SoC (System-on-Chip) comprises of many subcomponents: timer, clock controller, I2C/SPI controller, GPIO, interrupt controller, SDHCI storage, USB, and so on. Each needs its own driver, and for most parts the exact implementation differs between chip manufacturers. Most of them expose a static range of addresses in MMIO (memory-mapped IO) space that the system can use to communicate with them.


Devicetrees are written in a plaintext format known as the '''Device Tree Source (DTS)''' format. The DTS is later compiled into a '''Device Tree Blob (DTB)'''; in this form, it can be loaded by software/firmware.
Additionally, there may be other peripherals connected to the system - often through a bus like I2C or SPI, or as a simple device controlled by a GPIO.


The <code>dtc</code> tool handles compiling DTS files into DTBs, as well as decompiling DTBs back into DTS.
On a standard x86 system, peripherals are usually autodetected, either through ACPI, or by being on a bus like PCI or USB. On most embedded platforms like ARM, however,  there is no such autodetection method, and the hardware needs to be described manually.


=== Device Tree Source basics ===
The solution for this, used by both the Linux kernel, as well as a variety of other projects like U-Boot, is the '''devicetree'''.


Here is a very simple DTS file to explain the basics of what you might see in a device tree source file:
The following is a very simple example DTS (device tree source):


<syntaxhighlight lang="dts">
<syntaxhighlight lang="dts" line>
/dts-v1/;
/dts-v1/;


Line 29: Line 24:
#address-cells = <1>;
#address-cells = <1>;
#size-cells = <1>;
#size-cells = <1>;
 
my_node: node1@1000 {
my_node: node1@1000 {
compatible = "vendor,foo";
compatible = "vendor,foo";
reg = <0x1000 0x54>;
reg = <0x1000 0x54>;
vendor,bar-factor = <0x2a>;
vendor,bar-factor = <0x2a>;
};
node2@2000 {
compatible = "vendor,bar";
reg = <0x2000 0xa4>;
vendor,baz-companion = <&my_node>;
};
};


Line 57: Line 46:
</syntaxhighlight>
</syntaxhighlight>


In this example, we define an empty DTS; in its root node (<code>/</code>), we place three nodes: a node named "node1" with a label "my_node" at address 0x1000, a node named "node2" at address 0x2000, and a node named "i2c-controller" at address 0x3000.
{{note|For a full guide to DTS syntax, see [[/DTS syntax]].}}


A node contains:
The devicetree acts like a map of the hardware; it describes where each component is in register space, and stores configuration values for them. It also describes components located on buses like I2C and SPI, and can carry some metadata about the board/device (like the RAM size/base address, model code or chassis type).
* A <code>compatible</code> value (here <code>"vendor,foo"</code>). This specifies what kind of component it is; Linux uses this information to load the correct driver.
* A <code>reg</code> value. In this case, the first parameter is the base address in memory (<code>0x1000</code>), and the second is the size it occupies (<code>0x54</code>). The amount of cells for the address and size are specified by the <code>#address-cells</code> and <code>#size-cells</code> properties of the root node, respectively.
** You might notice that the i2c-controller node defines another set of these <code>#address-cells</code> and <code>#size-cells</code> properties - this is because I2C devices contain their own subdevices with addresses ranging from 0x08 to 0x7f (todo verify), and they do not use a size.
* A custom vendor-specific property, <code>vendor,bar-factor</code>, which takes a number.


On node 2 there is also a property, <code>vendor,baz-companion</code>, which takes a pointer to another node - here the one we labeled "my_node".
Devicetrees are written in the '''DTS''' (Device Tree Source) format; the source file can then be compiled into a '''DTB''' (Device Tree Blob), which software can parse to get all the necessary information about a given platform.


== Verifying device tree bindings and device tree sources ==
On modern systems, the bootloader loads the DTB into a set place in memory; the Linux kernel then decodes the information from the DTB and initializes all the components based on it. (On 32-bit ARM, which predates widespread adoption of DTBs and DTB-capable bootloaders, an alternative mechanism exists in Linux to load a DTB appended to the kernel image).


The Linux kernel has tools for verifying the correctness of device tree schema bindings, as well as making sure that device tree sources (DTS) use the bindings correctly. These are useful when writing device sources; getting both of these checks to pass is also mandatory for upstream inclusion of a binding/DTS.
== History ==
 
The initial version of the devicetree standard was developed as part of the OpenFirmware initiative; from this standard, the Flattened Device Tree (FDT) emerged and was adopted by the Linux kernel for PowerPC platforms. Around 2009, discussions began to include FDT support for ARM[1]. It was eventually added and first device trees began to appear in 2011[2], although the format didn't see wider usage (especially in vendor kernels) until around 2013/2014.


=== Verifying DT bindings ===
Nowadays, the devicetree standard is managed by [https://www.devicetree.org/ devicetree.org]; they maintain the latest version of the [https://www.devicetree.org/specifications Devicetree Specification] and the related set of [https://github.com/devicetree-org/dt-schema core DT schema].


To verify all DT bindings, run:
Before the introduction of devicetrees, ARM kernels used '''board files'''. These were C files stored in <code>arch/arm/mach-*</code> which served a similar purpose to devicetrees - they contained structures for defining component configuration ("platform data"). Unlike device trees however, they could also define C functions, since they were regular C sources compiled into the kernel. Board files technically still exist (citation needed?), but are no longer in wide use.


<syntaxhighlight lang="shell-session">
== Devicetree sources in the Linux kernel ==
$ make dt_binding_check
</syntaxhighlight>


You can also verify only a specific binding by providing its filename in the <code>DT_SCHEMA_FILES</code> option. This option takes either a filename or a directory name:
TODO


<syntaxhighlight lang="shell-session">
== Verifying DTS files ==
$ make dt_binding_check DT_SCHEMA_FILES=brcm,bcm590xx.yaml  # Checks all bindings named brcm,bcm590xx.yaml
$ make dt_binding_check DT_SCHEMA_FILES=qcom    # Checks all bindings in any (sub)folder named "qcom"
$ make dt_binding_check DT_SCHEMA_FILES=/gpio/  # Checks all bindings in /gpio folder
</syntaxhighlight>


=== Verifying DTS files ===
The Linux kernel has tools for making sure that device tree sources (DTS) use the bindings correctly. These are useful when writing device sources; getting
the DT checks to pass is also mandatory for upstream inclusion of a DTS.


To verify all DTS files built with the selected defconfig options, run:
To verify all DTS files built with the selected defconfig options, run:
Line 106: Line 88:
$ make CHECK_DTBS=y DT_SCHEMA_FILES=trivial-devices.yaml qcom/sm8450-hdk.dtb
$ make CHECK_DTBS=y DT_SCHEMA_FILES=trivial-devices.yaml qcom/sm8450-hdk.dtb
</syntaxhighlight>
</syntaxhighlight>
== Working with DTC ==
The <code>dtc</code> tool handles compiling DTS files into DTBs, as well as decompiling DTBs back into DTS. (TODO: add instructions)


== See also ==
== See also ==
Line 111: Line 97:
* From Linux kernel documentation:
* From Linux kernel documentation:
** [https://docs.kernel.org/devicetree/bindings/dts-coding-style.html Devicetree Sources (DTS) Coding Style]
** [https://docs.kernel.org/devicetree/bindings/dts-coding-style.html Devicetree Sources (DTS) Coding Style]
** [https://docs.kernel.org/devicetree/bindings/writing-schema.html Writing Devicetree Bindings in json-schema]
** [https://docs.kernel.org/devicetree/bindings/writing-bindings.html DOs and DON’Ts for designing and writing Devicetree bindings]
** [https://docs.kernel.org/devicetree/bindings/submitting-patches.html Submitting Devicetree (DT) binding patches]
* On elinux.org:
* On elinux.org:
** [https://elinux.org/Device_Tree_Reference Device Tree Reference]
** [https://elinux.org/Device_Tree_Reference Device Tree Reference]

Latest revision as of 18:10, 20 February 2025

The devicetree (device tree, DT) is a tree structure that describes the hardware register layout and configuration of a device. In the Linux kernel, as well as in other DT-using projects like U-Boot, it is the primary method of discovering peripherals on embedded platforms such as ARM.

Devicetrees are written in a plaintext format known as the Device Tree Source (DTS) format. The DTS is later compiled into a Device Tree Blob (DTB); in this form, it can be loaded by software/firmware.

Devicetrees are validated using devicetree schema, which is described in DT bindings; see /Bindings for more information.

Introduction

An SoC (System-on-Chip) comprises of many subcomponents: timer, clock controller, I2C/SPI controller, GPIO, interrupt controller, SDHCI storage, USB, and so on. Each needs its own driver, and for most parts the exact implementation differs between chip manufacturers. Most of them expose a static range of addresses in MMIO (memory-mapped IO) space that the system can use to communicate with them.

Additionally, there may be other peripherals connected to the system - often through a bus like I2C or SPI, or as a simple device controlled by a GPIO.

On a standard x86 system, peripherals are usually autodetected, either through ACPI, or by being on a bus like PCI or USB. On most embedded platforms like ARM, however, there is no such autodetection method, and the hardware needs to be described manually.

The solution for this, used by both the Linux kernel, as well as a variety of other projects like U-Boot, is the devicetree.

The following is a very simple example DTS (device tree source):

/dts-v1/;

/ {
	#address-cells = <1>;
	#size-cells = <1>;

	my_node: node1@1000 {
		compatible = "vendor,foo";
		reg = <0x1000 0x54>;
		vendor,bar-factor = <0x2a>;
	};

	i2c-controller@3000 {
		compatible = "vendor,foobar-i2c";
		reg = <0x3000 0x800>;
		
		#address-cells = <1>;
		#size-cells = <0>;
		
		sensor@10 {
			compatible = "vendor,baz-sensor";
			reg = <0x10>;
		};
	};
};
Note For a full guide to DTS syntax, see /DTS syntax.

The devicetree acts like a map of the hardware; it describes where each component is in register space, and stores configuration values for them. It also describes components located on buses like I2C and SPI, and can carry some metadata about the board/device (like the RAM size/base address, model code or chassis type).

Devicetrees are written in the DTS (Device Tree Source) format; the source file can then be compiled into a DTB (Device Tree Blob), which software can parse to get all the necessary information about a given platform.

On modern systems, the bootloader loads the DTB into a set place in memory; the Linux kernel then decodes the information from the DTB and initializes all the components based on it. (On 32-bit ARM, which predates widespread adoption of DTBs and DTB-capable bootloaders, an alternative mechanism exists in Linux to load a DTB appended to the kernel image).

History

The initial version of the devicetree standard was developed as part of the OpenFirmware initiative; from this standard, the Flattened Device Tree (FDT) emerged and was adopted by the Linux kernel for PowerPC platforms. Around 2009, discussions began to include FDT support for ARM[1]. It was eventually added and first device trees began to appear in 2011[2], although the format didn't see wider usage (especially in vendor kernels) until around 2013/2014.

Nowadays, the devicetree standard is managed by devicetree.org; they maintain the latest version of the Devicetree Specification and the related set of core DT schema.

Before the introduction of devicetrees, ARM kernels used board files. These were C files stored in arch/arm/mach-* which served a similar purpose to devicetrees - they contained structures for defining component configuration ("platform data"). Unlike device trees however, they could also define C functions, since they were regular C sources compiled into the kernel. Board files technically still exist (citation needed?), but are no longer in wide use.

Devicetree sources in the Linux kernel

TODO

Verifying DTS files

The Linux kernel has tools for making sure that device tree sources (DTS) use the bindings correctly. These are useful when writing device sources; getting the DT checks to pass is also mandatory for upstream inclusion of a DTS.

To verify all DTS files built with the selected defconfig options, run:

$ make dtbs_check

To verify a specific DTS, build the DTB target directly and provide the CHECK_DTBS=y option:

$ make CHECK_DTBS=y qcom/sm8450-hdk.dtb

You can also test a DTS against a specific subset of bindings by providing the DT_SCHEMA_FILES variable as mentioned in the previous section:

$ make CHECK_DTBS=y DT_SCHEMA_FILES=trivial-devices.yaml qcom/sm8450-hdk.dtb

Working with DTC

The dtc tool handles compiling DTS files into DTBs, as well as decompiling DTBs back into DTS. (TODO: add instructions)

See also

References

todo enable refs extension

[1] https://www.mail-archive.com/[email protected]/msg01721.html [2] https://github.com/torvalds/linux/commit/b85a3ef4ac65169b65fd2fe9bec7912bbf475ba4