U-Boot Device Tree fixups

See how U-Boot modifies your board device tree

If you compare the device tree as loaded by Linux, available in /sys/firmware/fdt, you will see that it differs from the one that you loaded in U-Boot. Taking the time to make the comparison is quite instructive.

Let’s do this on my Toradex Verdin iMX8M Mini SoM on the Dahlia carrier board.

Decompiling the DTB

It’s easy to decompile any Device Tree Binary (DTB) file using dtc, the Device Tree Compiler.

  1. Copy /sys/firmware/fdt from your live Linux system to external storage (assuming your external storage is mounted on /mnt/usb)
    cp /sys/firmware/fdt /mnt/usb/linux.dtb
  2. Then, on your GNU/Linux PC, use dtc to get the corresponding Device Tree Source (DTS) format:
    dtc linux.dtb > linux.dts

You can do the same thing with the Device Tree originally passed to U-Boot:
dtc imx8mm-verdin-nonwifi-dahlia.dtb > imx8mm-verdin-nonwifi-dahlia.dts

Why not directly take the imx8mm-verdin-nonwifi-dahlia.dts source file in the kernel sources? Because that’s only a toplevel representation of the board Device Tree – you want to have the includes added and the values from headers expanded.

Bootloader DT fix-ups

U-Boot Device Tree fixups

Before booting the Linux kernel with the DTB file, the bootloader actually needs to make a few fix-ups to the Device Tree.

The most important reason is to pass the kernel command line to the kernel, but other pieces of information can be added too.

Let’s see these chances by ourselves on the Verdin iMX8M board.

Install text comparison tool

A great tool for comparing files is Meld:
sudo apt install meld

We can now compare the original DT with the modified one eventually loaded by Linux:
meld imx8mm-verdin-nonwifi-dahlia.dts linux.dts

What follows are screenshots of the various sections that we modified by U-Boot

Board information

Here you can seed that U-Boot detected and stored important board information, such as the board revision and serial numbers, as well as the amount of RAM. Linux needs such information, but it can vary from board to board. That’s particularly true for the board or SoC serial number. The amount of RAM can vary too. Think about the 2GB, 4GB, 8GB and 16GB variants of the Raspberry Pi 5 board. You don’t want to have four different DTS files in the kernel sources, corresponding to each variant.

MAC address

U-Boot fixups: MAC address

One thing that is expected to change from one board to another is the MAC address.

Kernel command line

U-Boot fixups: kernel command line

Here’s how the Linux kernel receives its command line string. A pleasant surprise (at least for me) is to find information about the U-Boot version too.

All this is stored in a special node called chosen, which unlike the rest of the Device Tree, is allowed to store Operating System specific information. The Device Tree is supposed to be OS agnostic, because it is meant to be used to describe the board hardware for any operating system or bootloader using it: Linux, U-Boot, Barebox, Op-tee, FreeBSD…

What to remember

Before starting the Linux kernel, U-Boot actually modifies the DTB file that you loaded:

  • To add information that can vary from one instance of the board to the next: amount of RAM, serial number, revision number, MAC address
  • To pass the kernel command line string

It was nice to see all these changes by ourselves in a concrete case.