Devicetree
The devicetree (device tree, DT) 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.
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, which is described by bindings; see /Bindings for more information.
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.
Device Tree Source (DTS) basics
The following is a simple DTS file to demonstrate the DTS syntax. For a more in-depth syntax guide, see Devicetree/DTS syntax.
/dts-v1/;
/ {
#address-cells = <1>;
#size-cells = <1>;
my_node: node1@1000 {
compatible = "vendor,foo";
reg = <0x1000 0x54>;
vendor,bar-factor = <0x2a>;
};
node2@2000 {
compatible = "vendor,bar";
reg = <0x2000 0xa4>;
vendor,baz-companion = <&my_node>;
};
i2c-controller@3000 {
compatible = "vendor,foobar-i2c";
reg = <0x3000 0x800>;
#address-cells = <1>;
#size-cells = <0>;
sensor@10 {
compatible = "vendor,baz-sensor";
reg = <0x10>;
};
};
};
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
- From Linux kernel documentation:
- On elinux.org:
References
todo enable refs extension
[1] https://www.mail-archive.com/[email protected]/msg01721.html [2] https://github.com/torvalds/linux/commit/b85a3ef4ac65169b65fd2fe9bec7912bbf475ba4