ROCK Pi 4: Blobless Bootloader

This page was last updated on December 9th, 2023.

One of the main reasons why I opted for the ROCK Pi 4A for my home server was that it runs fine with only (!) free software. So as bootloader I want to use Das U-Boot without any binary blobs. Here I wrote down how I installed U-Boot (mainline) first on a microSD card and then the soldered SPI flash.

Boot from microSD card

Originally I wanted to use the pre-built SD card installer image for the board provided by Debian. This image includes U-Boot and is part of Debian’s main archive area, so it must comply with the DFSG and thus be free software. See the last few paragraphs of this section to find out why this installer image turned out not to be a real option for me.

As explained in the README.concatenateable_images file I have to download a device-specific part (firmware.rock-pi-4-rk3399.img.gz) as well as a device-independent part (partition.img.gz) and then decompress and concatenate them.

$ wget
$ wget
$ zcat firmware.rock-pi-4-rk3399.img.gz partition.img.gz > sd_card_image.img

Now I use lsblk before and after I put in my microSD card to find out to which device file it is mapped (in my case that is /dev/sda), then I unmount all possibly mounted partitions and write the image. Be aware that after these steps all data on the microSD card will be lost.

$ lsblk
$ sudo umount /dev/sda?*
$ sudo dd if=sd_card_image.img of=/dev/sda
$ sync

Then I just have to insert the microSD card into my ROCK Pi 4 and connect the monitor, my keyboard and the AC adapter. The bootloader works as expected and Debian Installer starts. I could use it to install my root file system to my microSD card, probably to an eMMC (I didn’t try that, I don’t have one), to some USB mass storage device or an NVMe M.2 SSD. The bootloader however would still be on my microSD card and so I would have to keep it inserted… But I can’t.

As I wrote in my last post I’m planning to use my ROCK Pi 4 as a home server with an aluminum housing and an M.2 extension board since I want to place my NVMe M.2 SSD inside that housing. In this picture you can see the microSD card inserted before mounting the M.2 extension board on top of the ROCK Pi 4:

Now when I put the M.2 extension board on the standoff bolts with the microSD card inserted I can’t mount the aluminum part with the walls of the housing. And when I mount it without the microSD card inserted the ribbon cable covers the microSD slot…

So I definitely need another boot option. After looking at the Rockchip wiki I realized that I had two remaining options: SPI flash and eMMC. I decided to make use of the included SPI flash.

Boot from SPI flash

I couldn’t find a software project that provides an easy way to make use of the SPI flash of the ROCK Pi 4 with only free software. Armbian does provide an easy way indeed, but unfortunately the project’s builds depend on binary blobs. So I have to build U-Boot myself. The official U-Boot documentation, in this context especially the document for Rockchip supported boards, is really helpful.

Before I begin I have to get all the necessary tools. Working with Debian-based PureOS I use apt to get the required packages:

~$ sudo apt install build-essential gcc-aarch64-linux-gnu gcc-arm-none-eabi bison flex swig libncurses-dev libssl-dev uuid-dev libgnutls28-dev python3-dev python3-setuptools python3-pyelftools

The first step is to build TrustedFirmware-A (TF-A) which is required when building the U-Boot image for the ROCK Pi 4. I start by creating a directory for the build process and changing into it, then I download a tarball of TF-A v2.10, extract its contents and change into the new subdirectory:

~$ mkdir uboot-rockpi4
~$ cd uboot-rockpi4
~/uboot-rockpi4$ wget
~/uboot-rockpi4$ tar -xvf trusted-firmware-a-2.10.tar.gz
~/uboot-rockpi4$ cd trusted-firmware-a-2.10.tar.gz

The source code includes some binary files with unknown licensing. I follow the Debian project and simply remove those files before building TF-A:

~/uboot-rockpi4/trusted-firmware-a-2.10$ find -name \*.bin -exec rm -v {} \;
~/uboot-rockpi4/trusted-firmware-a-2.10$ make CROSS_COMPILE=aarch64-linux-gnu- PLAT=rk3399
~/uboot-rockpi4/trusted-firmware-a-2.10$ cd ..

Now I download a tarball of U-Boot v2023.10, extract its contents and change into the new subdirectory:

~/uboot-rockpi4$ wget
~/uboot-rockpi4$ tar -xvf u-boot-2023.10.tar.bz2
~/uboot-rockpi4$ cd u-boot-2023.10

Since U-Boot mainline doesn’t support the SPI flash of the ROCK Pi 4 yet I basically pieced together two patches I found at the Armbian build repository. You can download the resulting patch and apply it like this:

~/uboot-rockpi4/u-boot-2023.10$ wget
~/uboot-rockpi4/u-boot-2023.10$ patch -p1 < rockpi4-enable-spi-flash.patch

Now I ensure that the U-Boot build process can find the TF-A binary bl31.elf, then I use the template configuration file for the board to generate the configuration file and start the build process:

~/uboot-rockpi4/u-boot-2023.10$ export BL31=../trusted-firmware-a-2.10/build/rk3399/release/bl31/bl31.elf
~/uboot-rockpi4/u-boot-2023.10$ make rock-pi-4-rk3399_defconfig
~/uboot-rockpi4/u-boot-2023.10$ make CROSS_COMPILE=aarch64-linux-gnu-

My plan is to use the U-Boot command line to install the SPI boot image, so I write an U-Boot image that boots from a microSD card and then copy the SPI boot image to that same microSD card.

First I use lsblk before and after I insert the microSD card to make sure I use the correct device file (in my case it’s /dev/sda). After that I unmount all possibly mounted partitions. Be aware that after the next steps all data on the microSD card will be lost. I create a GPT disk label, a new partition and then build a file system on that partition. I’ll use this partition for the SPI boot image, note that it starts at sector 32768 to leave enough space in front of it for the U-Boot image that boots from the microSD card.

~/uboot-rockpi4/u-boot-2023.10$ lsblk
~/uboot-rockpi4/u-boot-2023.10$ sudo umount /dev/sda?*
~/uboot-rockpi4/u-boot-2023.10$ sudo parted /dev/sda mklabel gpt
~/uboot-rockpi4/u-boot-2023.10$ sudo parted /dev/sda mkpart noname ext4 32768s 100%
~/uboot-rockpi4/u-boot-2023.10$ sudo mkfs.ext4 /dev/sda1

Now I write the U-Boot image that boots from the microSD card:

~/uboot-rockpi4/u-boot-2023.10$ sudo dd if=u-boot-rockchip.bin of=/dev/sda seek=64
~/uboot-rockpi4/u-boot-2023.10$ sync

Finally I copy the SPI boot image to the microSD card. For that I mount the partition I created, copy the image and then unmount the partition again.

~/uboot-rockpi4/u-boot-2023.10$ sudo mkdir /media/sdcard
~/uboot-rockpi4/u-boot-2023.10$ sudo mount -t ext4 /dev/sda1 /media/sdcard
~/uboot-rockpi4/u-boot-2023.10$ sudo cp u-boot-rockchip-spi.bin /media/sdcard/
~/uboot-rockpi4/u-boot-2023.10$ sudo umount /media/sdcard
~/uboot-rockpi4/u-boot-2023.10$ sudo rmdir /media/sdcard

Let’s put the microSD card into the ROCK Pi 4, connect the display via HDMI, the keyboard via USB (there’s an issue with the USB 2 ports in U-Boot, so I use one of the USB 3 ports) and then the AC adapter. U-Boot starts and looks for a bootable OS but won’t find one. After that I can use the command line to flash the SPI boot image like this:

=> sf probe
=> load mmc 1:1 $kernel_addr_r u-boot-rockchip-spi.bin
=> sf update $fileaddr 0 $filesize

I can verify that U-Boot is installed on the SPI flash by removing the microSD card and then using the reset command (or by simply disconnecting and reconnecting the AC adapter). U-Boot starts from the SPI flash now, it looks for a bootable OS but won’t find one and after that drops to the shell again.

Now I use the command line to edit two environment variables to speed up the boot process. I want U-Boot to only search for a bootable OS first on a storage device attached via USB and then my NVMe SSD. And I don’t want U-Boot to wait seconds for user input to enter the shell, so I disable boot delay.

=> env set boot_targets "usb nvme"
=> env set bootdelay 0
=> env save

Finally, I connect a USB flash drive with the Debian network install image and my NVMe SSD and use the reset command to boot the Debian Installer.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

You can encrypt your comment so that only Stefan can read it.