The device tree solves a fundamental problem in embedded Linux: the kernel needs to know what hardware is present, but hardcoding that information into the kernel binary is inflexible and wasteful. The device tree provides a clean separation between the kernel and hardware description.
The Problem: Hardware Description
To manage hardware resources, the Linux kernel needs to know:
- Which I/O devices are present
- Their memory addresses and interrupt lines
- How they connect to each other
- Configuration parameters for each peripheral
There are two ways to provide this information:
Option 1: Hardcode into the Kernel Binary
The hardware definition is compiled directly into the kernel source code.
Problem: Any change to the hardware definition requires recompiling the entire kernel. For a product with multiple hardware revisions, this creates a different kernel binary for every board variant.
Option 2: Device Tree Blob (DTB)
The hardware definition is stored in a separate file — the device tree blob — that is passed to the kernel by the bootloader at boot time.
Advantage: Hardware definitions can be changed by recompiling only the device tree source file. The kernel binary remains unchanged.
Without Device Tree:
Hardware Change --> Recompile Kernel --> Flash new kernel
With Device Tree:
Hardware Change --> Recompile DTB only --> Flash new DTB
(kernel unchanged)
Device Tree Files
The device tree toolchain involves three file types:
| File Type | Extension | Description |
|---|---|---|
| Device Tree Source | .dts | Human-readable text description of hardware |
| Device Tree Include | .dtsi | Shared device tree fragments (included by .dts) |
| Device Tree Blob | .dtb | Compiled binary form passed to the kernel |
Device Tree Source (.dts)
|
| dtc (device tree compiler)
v
Device Tree Blob (.dtb)
|
| bootloader passes to kernel
v
Linux Kernel reads and initialises drivers
Device Tree Blob (DTB)
A Device Tree Blob (DTB) is the binary representation of the device tree. It is:
- Produced by compiling the device tree source (
.dts) file with the Device Tree Compiler (dtc) - Stored on the same storage medium as the kernel (eMMC, SD card, NOR flash)
- Passed to the kernel by the bootloader as part of the boot process
The kernel reads the DTB at startup and uses the information to:
- Discover which drivers to initialise
- Configure each driver with the correct parameters (base address, IRQ number, clock frequency, etc.)
- Understand the interconnect topology between devices
Device Tree Source Structure
A device tree source file describes hardware as a tree of nodes, where each node represents a hardware component.
/dts-v1/;
/ {
model = "My Embedded Board";
compatible = "vendor,board";
memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x10000000>; /* 256 MB at 0x80000000 */
};
serial@10009000 {
compatible = "arm,pl011";
reg = <0x10009000 0x1000>;
interrupts = <0 5 4>;
clocks = <&uart_clk>;
};
ethernet@10010000 {
compatible = "smsc,lan9118";
reg = <0x10010000 0x10000>;
interrupts = <0 15 4>;
};
};
Key node properties:
| Property | Description |
|---|---|
compatible | String that matches a driver in the kernel |
reg | Memory address and size of the device |
interrupts | Interrupt controller and interrupt number |
clocks | Clock source reference |
How the Bootloader Passes the DTB
During the boot sequence, the bootloader:
- Loads the kernel image into RAM
- Loads the DTB into RAM (at a different address)
- Passes the DTB address to the kernel via a CPU register before jumping to the kernel entry point
Boot Sequence:
Bootloader loads kernel to 0x80008000
Bootloader loads DTB to 0x83000000
|
| Set register r2 = 0x83000000 (DTB address)
v
Kernel entry point
|
| Read DTB from r2
v
Kernel parses device tree
|
v
Kernel initialises drivers based on device tree
Device Tree in U-Boot
When using U-Boot as the bootloader, the DTB is typically loaded and passed to the kernel using boot commands:
# Load kernel and DTB from SD card
load mmc 0:1 ${kernel_addr_r} zImage
load mmc 0:1 ${fdt_addr_r} board.dtb
# Boot with device tree
bootz ${kernel_addr_r} - ${fdt_addr_r}
Modifying the Device Tree
When you add new hardware to an existing board, or change peripheral configuration, you only need to:
- Edit the
.dtsfile - Recompile to produce a new
.dtb - Flash the new
.dtbto the board
The kernel does not need to be recompiled. This is a major time saver during hardware bring-up and product iterations.
# Compile a device tree source file
dtc -I dts -O dtb -o board.dtb board.dts
# Decompile a DTB back to readable source
dtc -I dtb -O dts -o board.dts board.dtb
Final Thoughts
The device tree is one of the most important concepts in embedded Linux development. It enables:
- Reuse of the same kernel binary across different hardware
- Maintainability — hardware changes require only DTB updates
- Clarity — the hardware description is explicit and readable
Device Tree Role:
Hardware Platform
|
| described by
v
Device Tree Source (.dts)
|
| compiled to
v
Device Tree Blob (.dtb)
|
| passed to kernel by bootloader
v
Linux Kernel: initialises correct drivers
Understanding the device tree is essential for embedded Linux board bring-up, driver development, and hardware customisation.