User:Brendlefly62/Rockchip RK3288 Asus Tinker Board S/Build-Install-U-Boot
There are a number of places you can find pre-built images to boot your TInkerBoard S. This guide describes how to set up Das U-Boot bootloader, using another arm device or on an amd64 crossdev platform, by building the bootloader firmware from mainline upstream source code.
Acknowledgement: This article is largely based on a similar work done for the Rock4c+
Shortcut
It really isn't necessary to do all the work outlined in the next section below, if the user has already performed the armbian/build process for producing an Armbian system for this board, as described in the previous section. Part of the output of that process is a debian package containing the u-boot files for the TinkerBoard and a script that explains how to install them --
user $
tree ./armbian-build-output/
|-- debs ... | `-- linux-u-boot-tinkerboard-current_23.11.0-trunk_armhf__2022.04-Se4b6-P0e83-H0e2e-Vc2b8-Bd32f-R448a.deb ...
Extract the contents of the u-bood .deb package
user $
cd armbian-build
user $
dpkg-deb -x ./debs/linux-u-boot-tinkerboard-current_23.11.0-trunk_armhf__2022.04-Se4b6-P0e83-H0e2e-Vc2b8-Bd32f-R448a.deb u-boot
user $
tree u-boot
u-boot/ `-- usr
|-- lib | |-- linux-u-boot-current-tinkerboard | | |-- rk3288_boot.bin | | `-- u-boot-rockchip-with-spl.bin | `-- u-boot | |-- LICENSE | |-- platform_install.sh | `-- tinker-rk3288_defconfig `-- share `-- doc `-- linux-u-boot-tinkerboard-current`-- changelog.gz
Examine (but Do Not execute) the "platform_install.sh" script:
user $
cd u-boot
user $
cat usr/lib/u-boot/platform_install.sh
DIR=/usr/lib/linux-u-boot-current-tinkerboardwrite_uboot_platform () {
dd if=/dev/zero of=$2 bs=1k count=1023 seek=1 status=noxfer > /dev/null 2>&1; dd if=$1/u-boot-rockchip-with-spl.bin of=$2 seek=64 conv=notrunc > /dev/null 2>&1}
This script is basically the how-to for putting the already-built secondary program loader (SPL) onto a micro SD card that will hold a Gentoo OS and custom kernel.
Use a blank micro SD card. If you already have installed system files in an appropriate partition on the SD Card, then **Do Not** execute the first dd command in the "platform_install.sh" script - that will erase the partition table and all data on the device will be lost
Only the "u-boot-rockchip-with-spl.bin" file is needed for this boardAlso make sure to replace "sdX" below with the right device name
Use the structure of the first dd command to erase the beginning of the boot device, and then the structure of the second "dd" command in that script to write the "with-spl.bin" file to the device
root #
dd if=/dev/zero of=/swc/sdX bs=1k count=1023 seek=1 status=noxfer > /dev/null 2>&1
root #
dd if=lib/linux-u-boot-current-tinkerboard/u-boot-rockchip-with-spl.bin of=/dev/sdX seek=64 conv=notrunc > /dev/null 2>&1
The board should now be "bootable" and will display u-boot output on serial console when powered on.
(Update) The procedure above was used by the author in November 2023, and at the time, Armbian was employing an extlinux boot method to provide final instructions to the u-boot SPL. As of February 11, 2024, Armbian had begun using a boot.scr script to provide a bit more user-flexibiltiy and to load more overlays, giving the out-of-the-box Armbian system more functionality. The procedure above is still concpetually valid, but the updated dd command in the new script used by Armbian looks like this
write_uboot_platform () { ... dd if=/dev/zero of=$2 bs=32k count=63 seek=1 status=noxfer > /dev/null 2>&1; dd if=$1/$UBOOT_SRC of=$2 bs=32k seek=1 conv=notrunc }
So, from the u-boot root of the tree shown above, updated commands to erase the beginning of the boot device and load the SPL are
root #
OUT_FILE=/dev/sdX
root #
UBOOT_SRC=./usr/lib/linux-u-boot-current-tinkerboard/u-boot-rockchip-with-spl.bin
root #
dd if=/dev/zero of=$OUT_FILE bs=32k count=63 seek=1 status=noxfer > /dev/null 2>&1
root #
dd if=$UBOOT_SRC of=$OUT_FILE bs=32k seek=1 conv=notrunc
Alternative procedure (DIY)
Try this Do-it-yourself method to build u-boot from scratch User:Brendlefly62/Rockchip RK3288 Asus Tinker Board S/Build-Install-U-Boot/DIY u-boot
Observing boot message with serial console
Before installing a Linux operating system, check to ensure that U-Boot is booting correctly. It may be possible to use a USB-to-TTL connector (such as this one or this one), though the author has found that those are not supported by Windows 11. Instead, the author used a mini-usb FTDI board such as are commonly used to program AVR microcontrollers that lack on-board USB support (see photo) and used PuTTy software on a Windows 11 desktop PC to monitor the serial console.
Connect the USB-TTL converter device ground pin to pin 34 (GND), its TX pin to pin in 36 (UART3_RX), and its RX pin to pin 37 (UART3_TX) See also the TInkerBoard Developer Guide for reference) to see the early boot up messages:
root #
screen /dev/ttyUSB0 115200
* Make sure RX and TX are not backwards
Optional: Adapting baud rate
Serial communication usually requires both sides of the communication to agree on a common baud rate. Though the tinker-s-rk3288_defconfig default seems to be set to 115200 baud, Rockchip otherwise normally defaults to 1500000 bauds, which may be too fast for common USB-to-serial adapters. This may garble or prevent visibility of boot-messages from u-boot. A much more common and widely supported, but slower baud rate is 115200 bauds. U-Boot can be configured to use this slower baud rate.
Use menuconfig
as described in #Build_U-Boot and reconfigure the symbol BAUDRATE
to 115200
. Rebuild u-boot and copy it to the SD-card. Now start your program of choice for serial communication
Linux PC as external serial console
root #
screen /dev/ttyUSB0 115200
Window s PC for external serial console
Expected boot messages
Now put the card into the device and power on. If successful, you should be able to see output like this (click to expand):
<<<...This is output from Radxa Rock 4c+ -- replace with Tinker S spl output when working...>>> U-Boot TPL 2023.07.02 (Sep 24 2023 - 23:39:53) lpddr4_set_rate: change freq to 400MHz 0, 1 Channel 0: LPDDR4, 400MHz BW=32 Col=10 Bk=8 CS0 Row=16 CS=1 Die BW=16 Size=2048MB Channel 1: LPDDR4, 400MHz BW=32 Col=10 Bk=8 CS0 Row=16 CS=1 Die BW=16 Size=2048MB 256B stride lpddr4_set_rate: change freq to 800MHz 1, 0 Trying to boot from BOOTROM Returning to boot ROM... U-Boot SPL 2023.07.02 (Sep 24 2023 - 23:39:53 -0400) Trying to boot from MMC1 spl_load_fit_image: Skip load 'atf-5': image size is 0! NOTICE: BL31: v2.9(release):v2.9.0-dirty NOTICE: BL31: Built : 21:42:04, Sep 24 2023 U-Boot 2023.07.02 (Sep 24 2023 - 23:39:53 -0400) SoC: Rockchip rk3399 Reset cause: POR Model: Radxa ROCK Pi 4C DRAM: 4 GiB (effective 3.9 GiB) Core: 291 devices, 29 uclasses, devicetree: separate MMC: mmc@fe310000: 2, mmc@fe320000: 1, mmc@fe330000: 0 Loading Environment from MMC... Card did not respond to voltage select! : -110 *** Warning - No block device, using default environment In: serial Out: vidconsole Err: vidconsole Model: Radxa ROCK Pi 4C can't get vref-supply: -121 rockchip_dnl_key_pressed: adc_channel_single_shot fail! Net: eth0: ethernet@fe300000 Hit any key to stop autoboot: 0 ** Booting bootflow 'mmc@fe320000.bootdev.part_1' with script Loaded and running boot.scr!
* Early output from U-Boot TPL/SPL won't be shown on HDMI, only on serial
- You can press a key to interrupt the boot process and enter U-Boot's interactive shell
- You can find the list of commands and their syntax if you run
help
Booting a Linux system
Now that U-Boot installed on the SD card, the next step is to use it to boot a Linux system.
By default, U-Boot scans the partitions of each device (except SATA, see next section) to find something it knows how to load. The default supported file systems are ext2
, ext4
and FAT
, but there are a few others you can enable in U-Boot's menuconfig
. You will want your /boot partition to be formatted with one of those filesystems.
For TinkerBoard S using the miniloader boot flow described above, the boot directory should contain the kernel image, dtb file, and optional initrd and/or optional grub.efi. The extlinux/extlinux.conf file will identify the kernel (optionally initrd), and append text to the kernel command line, identifying the location of the rootfs. That should be all that is needed to boot this system. However, it is also possible to boot with a u-boot hush shell script compiled with the mkimage tool provided with u-boot sources or from the Gentoo dev-embedded/u-boot-tools package. Information about how to use that option follows in sections further below.
Verify extlinux.conf and /etc/fstab
root #
mount /dev/sdd2 /mnt/gentoo/
root #
mount /dev/sdd1 /mnt/gentoo/boot/
root #
cd /mnt/gentoo/boot/
root #
nano extlinux/extlinux.conf
kernel /zImage fdt /rk3288-tinker-s.dtbappend net.ifnames=0 earlyprintk quiet splash plymouth.ignore-serial-consoles console=tty1 root=/dev/mmcblk1p2 rw init=/sbin/init
root #
nano /mnt/gentoo/etc/fstab
UUID="aaaabbbb-cccc-dddd-1234-eeeeffff2222" / ext4 noatime 0 1 UUID="DDDD-CCCC" /boot vfat defaults 0 2 /var/cache/swap/swap1 none swap sw 0 0 /dev/mapper/vg_demo-srv /srv ext4 noatime 0 0
root #
cd
root #
umount -R /mnt/gentoo
root #
sync
Now remove the SD card from the reader, put it into the reader on the TinkerBoard S, and boot...
NO GO :-( ... This was attempted before Armbian tinker switched from extlinux to boot.scr; try again with boot.scr ...
Creating boot.scr [work in progress - draft copied from Rock4c+ page]
One thing it can load boot.scr
, which will contain commands for U-Boot to execute. This will be in your /boot partition along with your kernel and device tree binary.
First, create a file boot.cmd
. The example below includes a lot of extra stuff to facilitate exploration and debugging, but it can be significantly simplified --
echo "Loaded and running boot.scr!"
#setenv userEnv "joetooEnv.txt"
# defaults
setenv load_addr "0x9000000"
setenv overlay_error "false"
setenv rootdev "/dev/mmcblk0p1"
setenv verbosity "1"
setenv console "both"
setenv bootlogo "false"
setenv rootfstype "ext4"
if test -z "$bootargs"; then
setenv bootargs root=${rootdev} rootdelay=5
fi
# print some debugging info
echo "-----[ Initial State ]-----------------------------------"
#echo "userEnv..........: "${userEnv}
echo "load_addr........: "${load_addr}
echo "filesize.........: "${filesize}
echo "rootdev..........: "${rootdev}
echo "devtype..........: "${devtype}
echo "devnum...........: "${devnum}
echo "prefix...........: "${prefix}
echo "distro_bootpart..: "${distro_bootpart}
echo "verbosity........: "${verbosity}
echo "console..........: "${console}
echo "consoleargs......: "${consoleargs}
echo "bootlogo.........: "${bootlogo}
echo "rootfstype.......: "${rootfstype}
echo "earlycon.........: "${earlycon}
echo "overlays.........: "${overlays}
echo "overlay_prefix...: "${overlay_prefix}
echo "fdtfile..........: "${fdtfile}
echo "fdt_addr_r.......: "${fdt_addr_r}
echo "imagefile........: "${imagefile}
echo "kernel_addr_r....: "${kernel_addr_r}
echo "initrdfile.......: "${initrdfile}
echo "ramdisk_addr_r...: "${ramdisk_addr_r}
echo "partuuid.........: "${partuuid}
echo "usbstoragequirks.: "${usbstoragequirks}
echo "extraargs........: "${extraargs}
echo "extraboardargs...: "${extraboardargs}
echo "bootargs.........: "${bootargs}
echo "--------------------------------------------------------"
# Override/overwrite defaults per user's environment selections
echo "Ok - I am about to try reading joetooEnv.txt..."
if test -e ${devtype} ${devnum} ${prefix}joetooEnv.txt; then
load ${devtype} ${devnum} ${load_addr} ${prefix}joetooEnv.txt
env import -t ${load_addr} ${filesize}
else
echo "Did not find or load joetooEnv.txt"
fi
# Manage console settings
if test "${console}" = "display" || test "${console}" = "both"; then setenv consoleargs "console=tty1"; fi
if test "${console}" = "serial" || test "${console}" = "both"; then setenv consoleargs "console=ttyS2,115200 ${consoleargs}"; fi
if test "${earlycon}" = "on"; then setenv consoleargs "earlycon ${consoleargs}"; fi
if test "${bootlogo}" = "true"; then
setenv consoleargs "splash plymouth.ignore-serial-consoles ${consoleargs}"
else
setenv consoleargs "splash=verbose ${consoleargs}"
fi
# get PARTUUID of first partition on SD/eMMC the boot script was loaded from
if test "${devtype}" = "mmc"; then part uuid mmc ${devnum}:1 partuuid; fi
# update bootargs
#setenv bootargs "root=${rootdev} rootwait rootfstype=${rootfstype} ${consoleargs} consoleblank=0 loglevel=${verbosity} ubootpart=${partuuid} usb-storage.quirks=${usbstoragequirks} ${extraargs} ${extraboardargs}"
setenv bootargs "root=${rootdev} rootwait rootfstype=${rootfstype} ${consoleargs} consoleblank=0 loglevel=${verbosity} usb-storage.quirks=${usbstoragequirks} ${extraargs} ${extraboardargs}"
echo "-----[ Potentially Updated State ]-----------------------"
#echo "userEnv..........: "${userEnv}
echo "load_addr........: "${load_addr}
echo "filesize.........: "${filesize}
echo "rootdev..........: "${rootdev}
echo "devtype..........: "${devtype}
echo "devnum...........: "${devnum}
echo "prefix...........: "${prefix}
echo "distro_bootpart..: "${distro_bootpart}
echo "verbosity........: "${verbosity}
echo "console..........: "${console}
echo "consoleargs......: "${consoleargs}
echo "bootlogo.........: "${bootlogo}
echo "rootfstype.......: "${rootfstype}
echo "earlycon.........: "${earlycon}
echo "overlays.........: "${overlays}
echo "overlay_prefix...: "${overlay_prefix}
echo "fdtfile..........: "${fdtfile}
echo "fdt_addr_r.......: "${fdt_addr_r}
echo "imagefile........: "${imagefile}
echo "kernel_addr_r....: "${kernel_addr_r}
echo "initrdfile.......: "${initrdfile}
echo "ramdisk_addr_r...: "${ramdisk_addr_r}
echo "partuuid.........: "${partuuid}
echo "usbstoragequirks.: "${usbstoragequirks}
echo "extraargs........: "${extraargs}
echo "extraboardargs...: "${extraboardargs}
echo "bootargs.........: "${bootargs}
echo "-----[ now env print -a ]---------------------------------"
env print -a
# Load device tree file and kernel (to do: initramfs option)
# device tree - note that it finds the file in the "dtb" directory
echo "Loading device tree from ${devtype} ${devnum}:${distro_bootpart}..."
load ${devtype} ${devnum}:${distro_bootpart} ${fdt_addr_r} ${prefix}dtb/${overlay_prefix}/${fdtfile}
echo "Loading initrd from ${devtype} ${devnum}:${distro_bootpart}..."
load ${devtype} ${devnum} ${ramdisk_addr_r} ${prefix}${initrdfile}
echo "Loading kernel from ${devtype} ${devnum}:${distro_bootpart}..."
load ${devtype} ${devnum}:${distro_bootpart} ${kernel_addr_r} ${prefix}${imagefile}
# Load overlays (to do, if needed)
# Boot!
echo "Booting with arguments: ${bootargs}"
#booti ${kernel_addr_r} - ${fdt_addr_r}
booti ${kernel_addr_r} ${ramdisk_addr_r} ${fdt_addr_r}
# Recompile instruction
#
# Cross-compiling:
# cd to u-boot directory holding boot.cmd and run
# mkimage -C none -A arm64 -T script -d boot.cmd boot.scr
# then copy boot.scr, boot.cmd, and joetooEnv.txt to the /boot partition
# of your target system eMMC or microSD card
#
# If modifying an existing system (from said system)
# mkimage -C none -A arm64 -T script -d /boot/boot.cmd /boot/boot.scr
verbosity=6
earlycon=on
bootlogo=true
overlay_prefix=rockchip
fdtfile=rk3399-rock-4c-plus.dtb
imagefile=Image
initrdfile=uInitrd
rootdev=UUID=8870f459-a625-47c4-84f2-21f3a24b1818
rootfstype=ext4
extraargs=init=/sbin/init
usbstoragequirks=0x2537:0x1066:u,0x2537:0x1068:u
Be sure to change
rootdev=
to point to your actual root partition!
This can by done by UUID, as in this example, more portably than by path to block device, like "/dev/mmcblk0p1" -- but either way is validThen, compile it to boot.scr
:
root #
mkimage -C none -A arm64 -T script -d boot.cmd boot.scr
*
mkimage
can be used from either the bin directory in your U-Boot build directory or from dev-embedded/u-boot-tools
- Create a Makefile or a shell script so you don't have to look up the command above next time you need to edit
If the /boot partition is on microSD, it should work without additional steps.