Device Tree Overlay
- 14 Sep, 2025

Device Tree Intro
In the embedded system various busses can be used to connect peripherals to the CPU (directly or indirectly): system/platform, I2C, SPI, UART, USB, PCI, etc.
Some of these busses support automatic detection and enumeration of devices, which allows system to “recognize” the device that is connected and use it without a manual intervention.
However, many busses (like platform, I2C, SPI) do not have those capabilities, so there has to be a way to provide that information to the operating system, so those peripherals can be used.
In the x86 world, the BIOS contains the ACPI (Advanced COnfiguration and Power Interface) which provides that information to the OS. However, the ACPI is not used in the ARM world (there are some examples for the Aarch64 but not yet widespread).
Looking at the Linux kernel, in the beginning the hardware specifics for ARM systems were hardcoded in the kernel itself. This meant that for every board variant new C files had to be added.
This led to both kernel increasing in size and LOC, but also meant that a different kernel binary had to be used for each different variant of the board, which is a huge overhead.
That is where Device Tree (mandatory for ARM platforms since 2012) comes in handy.
The Device Tree description is used to provide the information about the hardware layout in a hierarchical form, from
processor configuration, over all system/platform busses and peripherals, to individual I2C and SPI components, and
more. The Device Tree Source (dts
) file is compiled into a Device Tree Blob (dtb
) using the Device Tree Compiler
(dtc
). The Device Tree Blob is then loaded at boot time by the bootloader and provided to the Linux kernel when
starting the system.
The peripherals in the Device Tree use compatible
strings to provide information to match the described peripheral
with a driver that can handle peripherals with the corresponding compatible
string. Also the base addresses and memory
ranges are specified, clocks, reset, interrupt and DMA configuration, GPIO configuration, pin mapping and multiplexing,
etc.
With the Device Tree descriptions, the same kernel can be used across multiple different variants of a board, even between different boards. For more details on the Device Tree, the Open Firmware and Device Tree kernel document can be used.
Device Tree Overlay
Sometimes it is easier to work with differences between different board descriptions, rather than having the copy-pasted device trees with small differences. This is especially interesting when working with development kits where different I2C/SPI peripherals can be used at different times, or when different pin configurations are used.
In these cases it would be more practical to be able to use a base Device Tree description, and then just modify it on-the-fly depending on the usecase before Linux starts using it.
This is where Device Tree Overlays come into play. The Device Tree Overlay is used to specify differences that need to be applied to a base Device Tree description.
Writing Device Tree Overlay
The Device Tree Overlay syntax is the same as the regular Device Tree file, except that it must have the
/plugin/;
in the start of the description.
In the example of the I2C driver for the Custom peripheral, the Device Tree patch that was used looked like
diff --git a/arch/arm/boot/dts/allwinner/sun4i-a10-cubieboard.dts b/arch/arm/boot/dts/allwinner/sun4i-a10-cubieboard.dts
index 787e018f6..4f4de36ec 100644
--- a/arch/arm/boot/dts/allwinner/sun4i-a10-cubieboard.dts
+++ b/arch/arm/boot/dts/allwinner/sun4i-a10-cubieboard.dts
@@ -139,6 +139,11 @@ axp209: pmic@34 {
reg = <0x34>;
interrupts = <0>;
};
+
+ i2csens: sens@36 {
+ compatible = "mistra,i2csens";
+ reg = <0x36>;
+ };
};
&i2c1 {
The I2C sens device was put under the i2c0 controller in the Cubieboard Device Tree description. The corresponding Device Tree Overlay would look like
// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
/*
* Copyright 2025 Strahinja Jankovic <strahinja@mistrasolutions.com>
*/
// CubieboardNG Custom QEMU I2C driver
/dts-v1/;
/plugin/;
/ {
compatible = "cubietech,a10-cubieboard", "allwinner,sun4i-a10";
};
&i2c0 {
#address-cells = <1>;
#size-cells = <0>;
status = "okay";
i2csens: sens@36 {
compatible = "mistra,i2csens";
reg = <0x36>;
};
};
The advantages of using Device Tree Overlay instead of patching (or modifying) the Device Tree are that it is modular and the decision to use it is moved from compile time to runtime (boot time to be specific).
More details on the Device Tree Overlay can be found in the Kernel documentation notes
Enabling support for the Device Tree Overlays
In order for U-Boot to be able to handle Device Tree Overlays, the following configuration needs to be enabled
CONFIG_OF_LIBFDT_OVERLAY=y`
CONFIG_CMD_FDT=y
The first option enables the Overlay support, and the second one adds the ftd
command that can be used to apply the
Overlay at runtime.
Additionally, the base Device Tree and the Overlay have to be compiled with the -@
option, to enable the symbol table.
Adding to Yocto
In case Yocto is used, the following changes in the Linux kernel recipe have to be made (assuming
cubieboard-ng-i2csens-overlay.dtso
is placed in the correct directory)
- Enable the
-@
option by adding it toKERNEL_DTC_FLAGS
KERNEL_DTC_FLAGS += "-@"
- Add the Device Tree Overlay source file to the
SRC_URI
SRC_URI:append = " file://cubieboard-ng-i2csens-overlay.dtso;subdir=linux-${PV}/arch/arm/boot/dts/allwinner"
- Add the Overlay Blob to the
KERNEL_DEVICETREE
variable
KERNEL_DEVICETREE:append = " allwinner/cubieboard-ng-i2csens-overlay.dtbo"
Applying the Device Tree Overlay
The Device Tree Overlay can be applied from U-Boot, before the Linux kernel is loaded.
The U-Boot fdt
command is used to set the base Device Tree Blob loaded in the memory, then resize it so overlay can be
applied and then to apply the Overlay blob
(documentation).
The steps are shown in the following excerpt
# Load device tree and overlay
setenv i2c_overlay cubieboard-ng-i2csens-overlay.dtbo
load mmc 0:${rootpart} ${fdt_addr_r} boot/${fdtfile}
load mmc 0:${rootpart} ${fdtoverlay_addr_r} boot/${i2c_overlay}
fdt addr ${fdt_addr_r}
fdt resize
fdt apply ${fdtoverlay_addr_r}
# Proceed to load and start the kernel
...
After this, the Device Tree description is updated and Linux can be started.
Tip
The full list of changes needed to support the Device Tree Overlay for the I2C device driver are in the scarthgap branch of the meta-mistra repository.
Summary
The Device Tree Overlay can help support different hardware extensions without having to change the base device tree description. It is very practical when working with different configurations since the changes are modular and can be applied at boot time.