Linux needs deep understanding of the hardware it is running on. Without this it either cannot function, or cannot take full advantage of hardware features. While most peripherals can be probed to find out what they are (SCSI, USB, UFS, etc.), we need a way to know about the core hardware, such as the USB controller, GPIO controller and clocks .
For x86 devices, the intent was that “all internal devices are PCI and PCI is plug-and-play”, so Linux can just scan the hardware and figure everything out from there. This isn’t always realistic. PCI may tell Linux that there is a GPIO available. Linux can happily turn it on and off. But what does it do? Does it control the LCD backlight, power to the WiFi module or a halt-and-catch-fire circuit?
ACPI tables bridge this gap, providing some context on top of the devices, as well as a way to describe things which are not plug-and-play. All x86 devices include ACPI tables in their firmware, typically 100-500KB.
The devicetree approach
Since 2011 ARM devices have used devicetree. Devicetree is unlike ACPI in almost every respect, except that it also describes hardware. Since plug-and-play was considered too expensive for embedded systems (ROMs everywhere!) and PCI was too power-hungry, devicetree often describes a system in considerable detail.
Devicetree files are specific to each device, although large chunks are common across SoC vendors, SoCs, etc. A devicetree file can easily be 80KB. If you have ever downloaded the datasheet for a modern SoC you might be surprised to learn it isn’t 800KB. Watch this space.
In theory, devicetree describes the hardware. Since the non-plug-and-play hardware on your device doesn’t change after manufacture, the devicetree should be set in stone at the start, right? But is it?
What if a new Linux version adds support for an audio DSP that was previously ignored? Perhaps the original devicetree had a bug?
In the ACPI world, these sorts of things are dealt with using a firmware update, traditionally a rare, inconvenient and scary thing. Even then, this isn’t universally true, since Operating Systems include code to work around ACPI-table bugs, replace or augment tables, etc. But when a new feature is added to Windows, the OEM provides a closed-source Windows driver and the hardware just works, ACPI table or no.
So back to devicetree. One option is to ask the vendor to create a firmware update with the new devicetree. That might take a while. Worse, you may want to boot two different versions of Linux, but each needs a slightly different devicetree to work properly. This shouldn’t happen, but it is common enough that Linux distros typically ship the devicetree as part of the OS.
But distros need to support a large array of hardware, so this does not scale very well. For example, if you build arm64 Linux with ‘make image.fit’ the compressed devicetrees take up more space than the kernel itself. That’s just for the hardware that vendors have got around to upstreaming!
What to do?
Really, we need to provide a devicetree in firmware and allow the OS to provide an updated version, or perhaps an overlay with a few changes. Even better, perhaps we can create a disk partition for the devicetrees, so they can be updated independently of the firmware, perhaps by a vendor-specific download?
How can this be done?
With U-Boot, if you have the OS in one FIT and the devicetrees in another, it is actuall possible to load both with something like:
bootm ${kernel_addr_r}#conf1 – ${fdt_addr_r}#conf1
assuming that both FITs have been loaded into memory.
In practice this is not very convenient, since it requires handling the loading separately for the two images. The solution is probably to add a new bootmeth which understands this approach. Some prototyping has been done so watch this space!


