You can skip the next several sections that document my failed attempt to follow instructions and use Docker. Continue on to the section that says "Forget Docker" and you will see I had success without any of that.
My goal is just to build what he calls the "boot image", which has U-boot and the necessary BL31 image from "arm trusted firmware (ATF)".
docker build -t sd-images https://github.com/johang/sd-card-images.git mkdir -p /tmp/sd-images docker run --rm -v /tmp/sd-images:/artifacts sd-images build-boot raspberrypi_3b bcm2837 rpi_3_defconfig aarch64-linux-gnuI have never had any dealings with "docker", but I suppose we can give it a try. He says the above process will leave the boot image in /tmp/sd-images.
su dnf install docker dnf updateThe install removes some selinux files -- which is fine by me, I have selinux disabled.
I do the dnf update simply because things on my system are quite out of date. I will also end up needing to reboot. I get some weird error about Nvidia modules not building properly. I know this has something to do with me installing CUDA development tools on my machine, which have conflicts with the drivers I use to run my system. All this has nothing to do with docker, so we will try to ignore it for now. But it turns ugly. I spend an hour or so getting rid of the entire CUDA package set.
I find this nice tutorial:
Of course all tutorials seem nice at first. I run into my first problem right away:docker run hello-world docker: permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sockIt works as root, which tells me that the docker daemon is running properly. It does go fetch the hello world thing from the "docker hub" for me. Some searching tells me that it is not the best idea to run docker as root. I edit /etc/group and add "tom" to the docker group. I have to log out and back in again for this to take effect. Docker gives me a bunch of tips and suggests trying:
docker run -it ubuntu bashThis pulls an "ubuntu:latest" image from the hub and runs it for me.
docker build -t sd-images https://github.com/johang/sd-card-images.gitThis fails. A look at the error message shows that it is trying to do something with apt-get. I don't know enough to tell if this is simply because I am running on Fedora, or whether it is trying to run things in a debian docker image -- but this is turning into much more of a tangle than I want to dive into. I peek a little more after I clone his repository and see that all this is coming from the "Dockerfile" which seems to specify a ubuntu image. As a Docker beginner, this is above my pay grade.
cd Projects/RK3328 git clone https://github.com/johang/sd-card-images.git cd sd-card-imagesHere is the line he said would build the boot image for a rpi-3:
docker run --rm -v /tmp/sd-images:/artifacts sd-images build-boot raspberrypi_3b bcm2837 rpi_3_defconfig aarch64-linux-gnuI squint at this and see the tail end is the command:
build-boot raspberrypi_3b bcm2837 rpi_3_defconfig aarch64-linux-gnuIn "scripts" is a shell script named "build-boot" that extracts and renames 4 arguments:
BOARD_ID = raspberrypi_3b CHIP_ID = bcm2837 DEFCONFIG = rpi_3_defconfig TUPLE = aarch64-linux-gnuIt then has a long case/switch on CHIP_ID.
build-boot-rk "${BOARD_ID}" "${CHIP_ID}" "${DEFCONFIG}" "${TUPLE}"
Stepping back a bit. I grep for "3328" and find the following lines.
What are these csv files for?
My guess is that he has a top level script that automates the build process
for all the boards in his collection.
boards.csv:orangepi_r1_plus_lts,Orange Pi R1 Plus LTS,Xunlong,rk3328,orangepi-r1-plus-lts-rk3328_defconfig,aarch64-linux-gnu,rk3328-orangepi-r1-plus-lts chips.csv:rk3328,RK3328,Rockchip,ARM Cortex A53,armv8,arm64Squinting at these lines in the CSV file, I can guess the following:
BOARD_ID = orangepi_r1_plus_lts CHIP_ID = rk3328 DEFCONFIG = orangepi-r1-plus-lts-rk3328_defconfig TUPLE = aarch64-linux-gnuSo, I could invoke "build-boot" as:
build-boot orangepi_r1_plus_lts rk3328 orangepi-r1-plus-lts-rk3328_defconfig aarch64-linux-gnuPoking around yet more I discover docs/_boards/orangepi_r1_plus_lts.md -- This looks like more stuff for his automated scheme and not relevant to what I am doing right now.
# DO NOT EDIT - Generated by rebuild-jekyll-boards layout: board title: Orange Pi R1 Plus LTS SD card images description: "Minimal, pure and up-to-date vanilla Debian/Ubuntu arm64 SD card images for Orange Pi R1 Plus LTS by Xunlong, SoC: Rockchip RK3328, CPU ISA: armv8" board_id: orangepi_r1_plus_lts board_dtb_name: rk3328-orangepi-r1-plus-lts board_name: Orange Pi R1 Plus LTS board_maker_name: Xunlong board_soc_name: Rockchip RK3328 board_cpu_name: ARM Cortex A53 (armv8) board_cpu_arch_isa: armv8 board_cpu_arch_debian: arm64
git clone --depth 1 --reference-if-able https://github.com/rockchip-linux/rkbin.git rkbinI just do this:
cd Projects/RK3328 mkdir sources cd sources git clone https://github.com/rockchip-linux/rkbin.gitThe webpage is here. You can ask google chrome to translate the Chinese for you.
build-atf "${CHIP_ID}" "${TUPLE}"
export BL31="$PWD/arm-trusted-firmware/build/${CHIP_ID}/debug/bl31/bl31.elf"
build-u_boot "${DEFCONFIG}" "${TUPLE}"
The sources are:
https://github.com/ARM-software/arm-trusted-firmware.git https://source.denx.de/u-boot/u-boot.git/I clone these for now. I am somewhat surprised that the "official" sources for each of these is what is used -- and I am pleased.
cd arm-trusted-firmware make PLAT="rk3328" DEBUG=1 bl31
I do this, and it just works with no errors or hassles and the build takes less than a minute.
Apparently PLAT is short for "platform".
DEFCONFIG = orangepi-r1-plus-lts-rk3328_defconfig
TUPLE = aarch64-linux-gnu
export BL31="$PWD/arm-trusted-firmware/build/${CHIP_ID}/debug/bl31/bl31.elf"
build-u_boot "${DEFCONFIG}" "${TUPLE}"
Or, in other words:
export BL31="$PWD/arm-trusted-firmware/build/rk3328/debug/bl31/bl31.elf" build-u_boot orangepi-r1-plus-lts-rk3328_defconfig aarch64-linux-gnuNote that the BL31 environment variable is set to tell U-boot where to find the bl31.elf image.
On my system, this will boil down to:
export BL31="/Projects/OrangePi/r1plus/sources/arm-trusted-firmware/build/rk3328/debug/bl31/bl31.elf" export CROSS_COMPILE=aarch64-linux-gnu- export LOCALVERSION="trebisky" cd u-boot make clean make orangepi-r1-plus-lts-rk3328_defconfig makeI get an error about a missing thing called "swig". This seems to be in relation to Python. On my Fedora system I try:
su dnf install swig makeOn to the next error, it is complaining that the C compiler cannot find Python.h There is some question of whether we need to specify python2 or python3, but I just do:
dnf install python-devel makeOn we go to another error. Apparently "engine" is deprecated as part of openssl, but lucky for us Fedora keeps a package for it anyway.
fatal error: openssl/engine.h: No such file or directory dnf install openssl-devel-engine makeOn we go to:
fatal error: gnutls/gnutls.h: No such file or directory dnf install gnutls-devel makeIt now goes a long ways, compiling all kinds of source files, but ends with this:
binman: Node '/binman/simple-bin/fit': subnode 'images/@atf-SEQ': Failed to read ELF file: Python: No module named 'elftools' dnf install python3-pyelftoolsThe build ends with this strange message:
Image 'simple-bin' is missing optional external blobs but is still functional: tee-os /binman/simple-bin/fit/images/@tee-SEQ/tee-os (tee-os): See the documentation for your board. You may need to build Open Portable Trusted Execution Environment (OP-TEE) and build with TEE=/path/to/tee.binIndeed this message comes out after the generation of "u-boot-rockchip.bin" so I am just going to ignore this "optional external blob".
When build-boot-rk is done, it does:
# Copy U-Boot to 64 sectors from start dd if=u-boot/u-boot-rockchip.bin of=tmp.img seek=64 conv=notruncThen back in build-boot, this happens:
truncate -s 32M tmp.img pigz tmp.imgI end up with this:
-rw-r--r-- 1 tom tom 550328 Dec 6 18:26 tmp.img.gz -rw-r--r-- 1 tom tom 540864 Nov 26 08:30 boot-orangepi_r1_plus_lts.bin.gzMy file is slightly bigger than what I downloaded 10 days ago, but it looks reasonable. Let's put it onto an SD card and try it.
unpigz tmp.img.gz dd if=tmp.img of=/dev/sdc bs=64MThe image is only 34M in size, so the copy is one partial record with this big blocksize.
And it works!. I even get to see my name on the version line.
U-Boot 2026.01-rc3trebisky-00026-g31bf4a1c3087 (Dec 06 2025 - 18:19:51 -0700)Finally, I customize the U-boot environment to do the usual network boot I like to use:
setenv linux bootflow scan
setenv loadaddr 0x02000000
setenv kyu echo Booting Kyu via dhcp/tftp\; dhcp\; go \${loadaddr}
setenv bootcmd run kyu
saveenv
It all works just fine.
Tom's electronics pages / tom@mmto.org