December 22, 2025

RK3399 - Linux device trees

We want to just skim over this, because in detail it is not relevant to what we are doing. We are looking at this because the U-boot "booti" command expects a device tree as a third argument, and throws a panic when I don't give it one.

It isn't clear yet if I can just give a pointer to trash in memory or if U-boot will validate what it finds there.

The device tree idea is a way to allow the linux kernel to contain generic device drivers with details (like base addresses, interrupt numbers, and such) to be supplied by a device tree. The idea was invented when the linux kernel developers found themselves confronted with a myriad of ARM based boards with minor differences in details. Rather than generating a custom kernel for each one, the hope was that one kernel could be generated and a device tree alongside of it could supply details. I'll be honest that I am skeptical. At least I have not found that much in common between the various ARM based boards I am working with. But I am not making the decisions, and this is clearly an entrenched practice at this stage.
Here is an explanation from the horses mouth:

The Zephyr link above seems to be the best explanation of the syntax. The Linux article explains the big concepts.

The syntax of the source files is one thing. Using the information in the tree from a device driver is something else entirely that I will ignore here. There is a well defined API for doing that and looking up information.

Getting started

First an xyz.dts file for a board is prepared. This is plain ascii. It is also possible (and common) to have abc.dtsi files ("i" for include). Then the dts file ("s" for source) is compiled into a dtb file ("b" for binary).
This is done with the "dtc" tool ("c" for compiler) as follows:

dtc -I dts -O dtb -o myboard.dtb myboard.dts
Note that it is also possible to run this the other way and decompile binary files you might find laying around.

On my Fedora system, I needed to install dtc:

su ; dnf install dtc
[3/4] Installing libfdt-0:1.7.2-3.fc42
[4/4] Installing dtc-0:1.7.2-3.fc42
U-boot itself uses device trees, and many other open source projects (NetBSD, FreeBSD, OpenWRT) do as wel. You can find examples in the U-boot source tree (in the dts directory) and in arch/arm/boot/dts for the linux kernel.

Here is a short bit of zynq-zc702.dts

/dts-v1/;
#include "zynq-7000.dtsi"

/ {
    model = "Xilinx ZC702 board";
    compatible = "xlnx,zynq-zc702", "xlnx,zynq-7000";

    aliases {
        ethernet0 = &gem0;
        serial0 = &uart1;
    };
    memory@0 {
        device_type = "memory";
        reg = <0x0 0x40000000>;
    };
	&uart1 {
		status = "okay";
		pinctrl-names = "default";
		pinctrl-0 = <&pinctrl_uart1_default>;
	};
};

A minimal device tree

I create the file "bogus.dts" as follows:
/* Bogus empty device tree
 */
/dts-v1/;

/ {
    model = "Totally bogus";
};
I use "dtc" to compile this, and it is totally happy with it:
dtc -I dts -O dtb -o bogus.dtb bogus.dts
I then present this to U-boot for use with the "booti" command as follows:
dhcp
tftpboot 03000000 bogus.dtb
booti 0x02000000 - 03000000
This works and satisfies U-boot, but I still find my code runs at EL2.
Have any comments? Questions? Drop me a line!

Tom's electronics pages / tom@mmto.org