User:Brendlefly62/Rockchip RK3288 Asus Tinker Board S/Build-Install-U-Boot/DIY u-boot
This procedure is under development -- it doesn't work yet, for this board
DIY Prerequisites
The outline below is a work in progress - attempt to document how to build a working u-boot bootloader from scratch. The documentation below is very rough draft and DOES NOT WORK. U-Boot can be built on an ARM device or cross-compiled on a PC. Regardless, we will need:
- git, to check out the sources
- dtc, to compile device trees
- swig, to build U-Boot
- crossdev, since a 32-bit ARM toolchain is required
Let's make sure these are installed:
root #
emerge --ask --update dev-vcs/git sys-apps/dtc dev-lang/swig sys-devel/crossdev
Please review the crossdev article if you don't already have it set up.
You may need to install the 32-bit toolchain, which is required to build code for Cortex-M0 MCUs in BL31:
root #
crossdev --target arm-none-eabi
If cross-compiling, install the 64-bit cross-compiler toolchain:
root #
crossdev --target armv7a-unknown-linux-gnueabihf
Compiling
To compile on ARM run commands like:
user $
make -j$(nproc) PLAT=rk3288 <target>
If cross-compiling, run:
user $
make -j$(nproc) PLAT=rk3288 CROSS_COMPILE=armv7a-unknown-linux-gnueabihf- <target>
If running distcc on the cross-compiling platform, it may be wise/necessary to disable that by temporarily removing '/usr/lib/distcc/bin' from your $PATH and turning off distcc in $FEATURES
user $
export PATH=$(echo $PATH | sed 's|/usr/lib/distcc/bin:||')
user $
MAKEOPTS="-j$(nproc) -l$(nproc)" FEATURES=$FEATURES" -distcc -distcc-pump" PLAT=rk3288 CROSS_COMPILE=armv7a-unknown-linux-gnueabihf- <target>
For Arm64 platforms, there is another pre-requisite step of building Arm Trusted Firmware "bl31" file, but as of Nov. 2023, the ATF Makefile says, "bl31 is not currently supported for aarch32.
Boot Loader alternatives
There are a number of ways to do this. This article describes one way to build a boot loader for TinkerBoard S using Arm Trusted Firmware (ATF or TF-A) and Das U-Boot. For detailed information on other methods, see link in the external resources and references secions, below.
Prepare to Build ATF
user $
git clone https://github.com/ARM-software/arm-trusted-firmware.git
user $
cd arm-trusted-firmware
user $
git tag
... v2.9.0
Select the latest currently stable version:
user $
git checkout v2.9.0
The repository contains a few binaries. If this is unacceptable, they may be deleted:
user $
for x in $(find ./ -iname *.bin); do rm -v $x; done
user $
git status
,,, deleted: plat/arm/board/common/protpk/arm_protpk_rsa_sha256.bin deleted: plat/arm/board/common/rotpk/arm_rotpk_ecdsa_sha256.bin deleted: plat/arm/board/common/rotpk/arm_rotpk_rsa_sha256.bin deleted: plat/arm/board/common/swd_rotpk/arm_swd_rotpk_rsa_sha256.bin deleted: plat/rockchip/rk3368/drivers/ddr/rk3368_ddr_reg_resume_V1.05.bin deleted: plat/rockchip/rk3399/drivers/dp/hdcp.bin ...
Per the ATF "How to Build" instructions,[1] compile (using an appropriately formatted command [see above]) the bl32 file that this board's u-boot will expect. According to the TF-A users guide, using the targets "all fip" will generate all of the bootloader binaries and a firmware information package (fip.bin) --
user $
MAKEOPTS="-j4 -l4" FEATURES=" -userpriv -distcc -distcc-pump" make ARCH=aarch32 PLAT=rk3288 CROSS_COMPILE=armv7a-unknown-linux-gnueabihf- AARCH32_SP=sp_min all fip
Including bl32/sp_min/sp_min.mk CC lib/libfdt/fdt.c CC lib/libfdt/fdt_addresses.c CC lib/libfdt/fdt_empty_tree.c CC lib/libfdt/fdt_ro.c CC lib/libfdt/fdt_rw.c CC lib/libfdt/fdt_strerror.c CC lib/libfdt/fdt_sw.c CC lib/libfdt/fdt_wip.c AR /home/joe/MyTinkerboardFiles/arm-trusted-firmware/build/rk3288/release/lib/libfdt.a Building rk3288 CC lib/libc/abort.c CC lib/libc/assert.c CC lib/libc/exit.c CC lib/libc/memchr.c CC lib/libc/memcmp.c CC lib/libc/memcpy.c CC lib/libc/memmove.c CC lib/libc/memrchr.c CC lib/libc/memset.c CC lib/libc/printf.c CC lib/libc/putchar.c CC lib/libc/puts.c CC lib/libc/snprintf.c CC lib/libc/strchr.c CC lib/libc/strcmp.c CC lib/libc/strlcat.c CC lib/libc/strlcpy.c CC lib/libc/strlen.c CC lib/libc/strncmp.c CC lib/libc/strnlen.c CC lib/libc/strrchr.c CC lib/libc/strtok.c CC lib/libc/strtoul.c CC lib/libc/strtoll.c CC lib/libc/strtoull.c CC lib/libc/strtol.c AR /home/joe/MyTinkerboardFiles/arm-trusted-firmware/build/rk3288/release/lib/libc.a CC bl32/sp_min/sp_min_main.c CC common/runtime_svc.c CC drivers/arm/cci/cci.c CC drivers/arm/gic/v2/gicdv2_helpers.c CC drivers/arm/gic/v2/gicv2_helpers.c CC drivers/arm/gic/v2/gicv2_main.c CC drivers/delay_timer/delay_timer.c CC drivers/delay_timer/generic_delay_timer.c CC lib/cpus/errata_report.c CC lib/el3_runtime/aarch32/context_mgmt.c CC lib/el3_runtime/cpu_data_array.c CC lib/locks/bakery/bakery_lock_coherent.c CC lib/psci/psci_common.c CC lib/psci/psci_main.c CC lib/psci/psci_mem_protect.c CC lib/psci/psci_off.c CC lib/psci/psci_on.c CC lib/psci/psci_setup.c CC lib/psci/psci_suspend.c CC lib/psci/psci_system_off.c CC plat/common/aarch32/plat_sp_min_common.c CC plat/common/plat_gicv2.c CC plat/rockchip/common/aarch32/platform_common.c CC plat/rockchip/common/params_setup.c CC plat/rockchip/common/plat_pm.c CC plat/rockchip/common/plat_topology.c CC plat/rockchip/common/rockchip_gicv2.c CC plat/rockchip/common/rockchip_sip_svc.c CC plat/rockchip/common/sp_min_plat_setup.c CC plat/rockchip/rk3288/drivers/pmu/pmu.c CC plat/rockchip/rk3288/drivers/secure/secure.c CC plat/rockchip/rk3288/drivers/soc/soc.c CC plat/rockchip/rk3288/plat_sip_calls.c CC services/std_svc/std_svc_setup.c CC common/bl_common.c CC common/tf_log.c CC drivers/console/multi_console.c CC plat/common/plat_bl_common.c CC plat/common/plat_log_common.c CC plat/common/aarch32/plat_common.c CC lib/compiler-rt/builtins/popcountdi2.c CC lib/compiler-rt/builtins/popcountsi2.c CC lib/compiler-rt/builtins/ctzdi2.c CC lib/compiler-rt/builtins/divdi3.c CC lib/compiler-rt/builtins/divmoddi4.c CC lib/compiler-rt/builtins/lshrdi3.c CC lib/compiler-rt/builtins/udivmoddi4.c CC common/desc_image_load.c CC lib/bl_aux_params/bl_aux_params.c CC plat/common/plat_psci_common.c CC lib/xlat_tables/xlat_tables_common.c CC lib/xlat_tables/aarch32/xlat_tables.c AS bl32/sp_min/aarch32/entrypoint.S AS bl32/sp_min/wa_cve_2017_5715_icache_inv.S AS drivers/ti/uart/aarch32/16550_console.S AS lib/cpus/aarch32/cortex_a12.S AS lib/cpus/aarch32/cpu_helpers.S AS lib/el3_runtime/aarch32/cpu_data.S AS lib/locks/exclusive/aarch32/spinlock.S AS lib/psci/aarch32/psci_helpers.S AS plat/common/aarch32/platform_mp_stack.S AS plat/rockchip/common/aarch32/plat_helpers.S AS plat/rockchip/common/aarch32/pmu_sram_cpus_on.S AS common/aarch32/debug.S AS lib/aarch32/cache_helpers.S AS lib/aarch32/misc_helpers.S AS plat/common/aarch32/platform_helpers.S AS lib/compiler-rt/builtins/arm/aeabi_ldivmod.S AS lib/compiler-rt/builtins/arm/aeabi_uldivmod.S AS lib/compiler-rt/builtins/arm/aeabi_memcpy.S AS lib/compiler-rt/builtins/arm/aeabi_memset.S AS plat/common/aarch32/crash_console_helpers.S PP bl32/sp_min/sp_min.ld.S LD /home/joe/MyTinkerboardFiles/arm-trusted-firmware/build/rk3288/release/bl32/bl32.elf Built /home/joe/MyTinkerboardFiles/arm-trusted-firmware/build/rk3288/release/bl32/bl32.elf successfully OD /home/joe/MyTinkerboardFiles/arm-trusted-firmware/build/rk3288/release/bl32/bl32.dump BIN /home/joe/MyTinkerboardFiles/arm-trusted-firmware/build/rk3288/release/bl32.bin Built /home/joe/MyTinkerboardFiles/arm-trusted-firmware/build/rk3288/release/bl32.bin successfully HOSTCC fiptool.c HOSTCC tbbr_config.c HOSTLD fiptool /usr/lib/gcc/x86_64-pc-linux-gnu/13/../../../../x86_64-pc-linux-gnu/bin/ld: skipping incompatible /usr/lib/libc.so when searching for -lc /usr/lib/gcc/x86_64-pc-linux-gnu/13/../../../../x86_64-pc-linux-gnu/bin/ld: skipping incompatible /usr/lib/libc.a when searching for -lc Built fiptool successfully Secure Payload BL32 (Trusted OS): offset=0x60, size=0xFF6E0018, cmdline="--tos-fw" Built /home/joe/MyTinkerboardFiles/arm-trusted-firmware/build/rk3288/release/fip.bin successfully
Locate the resulting bl32.elf --
user $
find ./ -iname bl32.elf
Note that the output files are stored in a "release" directory within a platform directory *"rk3288" inside the "build" sub-directory. The sturcture should look something like this
user $
tree build
build/ `-- rk3288 `-- release |-- bl32 | |-- 16550_console.d | |-- 16550_console.o | |-- aeabi_ldivmod.d | |-- aeabi_ldivmod.o | |-- aeabi_memcpy.d | |-- aeabi_memcpy.o | |-- aeabi_memset.d | |-- aeabi_memset.o | |-- aeabi_uldivmod.d | |-- aeabi_uldivmod.o | |-- bakery_lock_coherent.d | |-- bakery_lock_coherent.o | |-- bl32 | | `-- sp_min | | |-- sp_min.ld | | `-- sp_min.ld.d | |-- bl32.dump | |-- bl32.elf | |-- bl32.map | |-- bl_aux_params.d | |-- bl_aux_params.o | |-- bl_common.d | |-- bl_common.o | |-- build_message.o | |-- cache_helpers.d | |-- cache_helpers.o | |-- cci.d | |-- cci.o | |-- context_mgmt.d | |-- context_mgmt.o | |-- cortex_a12.d | |-- cortex_a12.o | |-- cpu_data.d | |-- cpu_data.o | |-- cpu_data_array.d | |-- cpu_data_array.o | |-- cpu_helpers.d | |-- cpu_helpers.o | |-- crash_console_helpers.d | |-- crash_console_helpers.o | |-- ctzdi2.d | |-- ctzdi2.o | |-- debug.d | |-- debug.o | |-- delay_timer.d | |-- delay_timer.o | |-- desc_image_load.d | |-- desc_image_load.o | |-- divdi3.d | |-- divdi3.o | |-- divmoddi4.d | |-- divmoddi4.o | |-- entrypoint.d | |-- entrypoint.o | |-- errata_report.d | |-- errata_report.o | |-- generic_delay_timer.d | |-- generic_delay_timer.o | |-- gicdv2_helpers.d | |-- gicdv2_helpers.o | |-- gicv2_helpers.d | |-- gicv2_helpers.o | |-- gicv2_main.d | |-- gicv2_main.o | |-- lshrdi3.d | |-- lshrdi3.o | |-- misc_helpers.d | |-- misc_helpers.o | |-- multi_console.d | |-- multi_console.o | |-- params_setup.d | |-- params_setup.o | |-- plat_bl_common.d | |-- plat_bl_common.o | |-- plat_common.d | |-- plat_common.o | |-- plat_gicv2.d | |-- plat_gicv2.o | |-- plat_helpers.d | |-- plat_helpers.o | |-- plat_log_common.d | |-- plat_log_common.o | |-- plat_pm.d | |-- plat_pm.o | |-- plat_psci_common.d | |-- plat_psci_common.o | |-- plat_sip_calls.d | |-- plat_sip_calls.o | |-- plat_sp_min_common.d | |-- plat_sp_min_common.o | |-- plat_topology.d | |-- plat_topology.o | |-- platform_common.d | |-- platform_common.o | |-- platform_helpers.d | |-- platform_helpers.o | |-- platform_mp_stack.d | |-- platform_mp_stack.o | |-- pmu.d | |-- pmu.o | |-- pmu_sram_cpus_on.d | |-- pmu_sram_cpus_on.o | |-- popcountdi2.d | |-- popcountdi2.o | |-- popcountsi2.d | |-- popcountsi2.o | |-- psci_common.d | |-- psci_common.o | |-- psci_helpers.d | |-- psci_helpers.o | |-- psci_main.d | |-- psci_main.o | |-- psci_mem_protect.d | |-- psci_mem_protect.o | |-- psci_off.d | |-- psci_off.o | |-- psci_on.d | |-- psci_on.o | |-- psci_setup.d | |-- psci_setup.o | |-- psci_suspend.d | |-- psci_suspend.o | |-- psci_system_off.d | |-- psci_system_off.o | |-- rockchip_gicv2.d | |-- rockchip_gicv2.o | |-- rockchip_sip_svc.d | |-- rockchip_sip_svc.o | |-- runtime_svc.d | |-- runtime_svc.o | |-- secure.d | |-- secure.o | |-- soc.d | |-- soc.o | |-- sp_min_main.d | |-- sp_min_main.o | |-- sp_min_plat_setup.d | |-- sp_min_plat_setup.o | |-- spinlock.d | |-- spinlock.o | |-- std_svc_setup.d | |-- std_svc_setup.o | |-- tf_log.d | |-- tf_log.o | |-- udivmoddi4.d | |-- udivmoddi4.o | |-- wa_cve_2017_5715_icache_inv.d | |-- wa_cve_2017_5715_icache_inv.o | |-- xlat_tables.d | |-- xlat_tables.o | |-- xlat_tables_common.d | `-- xlat_tables_common.o |-- bl32.bin |-- fip.bin |-- lib | |-- libc.a | `-- libfdt.a |-- libc | |-- abort.d | |-- abort.o | |-- assert.d | |-- assert.o | |-- exit.d | |-- exit.o | |-- memchr.d | |-- memchr.o | |-- memcmp.d | |-- memcmp.o | |-- memcpy.d | |-- memcpy.o | |-- memmove.d | |-- memmove.o | |-- memrchr.d | |-- memrchr.o | |-- memset.d | |-- memset.o | |-- printf.d | |-- printf.o | |-- putchar.d | |-- putchar.o | |-- puts.d | |-- puts.o | |-- snprintf.d | |-- snprintf.o | |-- strchr.d | |-- strchr.o | |-- strcmp.d | |-- strcmp.o | |-- strlcat.d | |-- strlcat.o | |-- strlcpy.d | |-- strlcpy.o | |-- strlen.d | |-- strlen.o | |-- strncmp.d | |-- strncmp.o | |-- strnlen.d | |-- strnlen.o | |-- strrchr.d | |-- strrchr.o | |-- strtok.d | |-- strtok.o | |-- strtol.d | |-- strtol.o | |-- strtoll.d | |-- strtoll.o | |-- strtoul.d | |-- strtoul.o | |-- strtoull.d | `-- strtoull.o |-- libfdt | |-- fdt.d | |-- fdt.o | |-- fdt_addresses.d | |-- fdt_addresses.o | |-- fdt_empty_tree.d | |-- fdt_empty_tree.o | |-- fdt_ro.d | |-- fdt_ro.o | |-- fdt_rw.d | |-- fdt_rw.o | |-- fdt_strerror.d | |-- fdt_strerror.o | |-- fdt_sw.d | |-- fdt_sw.o | |-- fdt_wip.d | `-- fdt_wip.o |-- libwrapper `-- romlib 11 directories, 222 files
Save a copy somewhere safe --
user $
cp -av ./build/rk3288 ../
Prepare to Build U-Boot
This example will build and use peer-level directories for u-boot and rkbin, within a common project directory, to simplify relative addressing of command line parameters
Return to the project directory and get u-boot sources. The u-boot sub-directory will be created in the process:
user $
cd ..
user $
git clone https://source.denx.de/u-boot/u-boot.git
user $
cd u-boot
user $
git tag
v2023.10
Check out latest currently stable version:
user $
git checkout v2023.10
Instead of cloning the complete u-boot repository as shown in the steps above, you may save some time and disc space by cloning branch v2023.10 only:
user $
git clone --depth 1 --branch v2023.10 https://source.denx.de/u-boot/u-boot.git
Identify and load board-specific default configuration
user $
find ./ -iname *rk3288*_defconfig | grep tinker
./configs/tinker-rk3288_defconfig ./configs/tinker-s-rk3288_defconfig
U-Boot boot-flow(s)
The Rockchip u-boot README[2] indicates that there are two possible boot-flows involving the use of either the rockchip "miniloader" or a TPL/SPL build with ATF. See much more detail at http://opensource.rock-chips.com/wiki_Boot_option In particular, note the details illustrated in the graphic at http://opensource.rock-chips.com/images/thumb/c/cd/Rockchip_bootflow20181122.jpg/894px-Rockchip_bootflow20181122.jpg Source -- http://opensource.rock-chips.com/wiki_Boot_option
Build u-boot
user $
MAKEOPTS="-j$(nproc) -l$(nproc)" FEATURES=$FEATURES" -distcc -distcc-pump" PLAT=rk3288 CROSS_COMPILE=armv7a-unknown-linux-gnueabihf- make O=tinker-s-rk3288_output BL32=../rk3288/release/bl32/bl32.elf tinker-s-rk3288_defconfig all
make[1]: Entering directory '/home/joe/MyTinkerboardFiles/u-boot/tinker-s-rk3288_output' HOSTCC scripts/basic/fixdep GEN Makefile HOSTCC scripts/kconfig/conf.o YACC scripts/kconfig/zconf.tab.c LEX scripts/kconfig/zconf.lex.c HOSTCC scripts/kconfig/zconf.tab.o HOSTLD scripts/kconfig/conf # # configuration written to .config # GEN Makefile scripts/kconfig/conf --syncconfig Kconfig CFG u-boot.cfg GEN include/autoconf.mk GEN include/autoconf.mk.dep CFG spl/u-boot.cfg GEN spl/include/autoconf.mk ... CC tpl/fs/fs_internal.o AR tpl/fs/built-in.o LDS tpl/u-boot-spl.lds LD tpl/u-boot-tpl OBJCOPY tpl/u-boot-tpl-nodtb.bin COPY tpl/u-boot-tpl.bin SYM tpl/u-boot-tpl.sym COPY u-boot.dtb MKIMAGE u-boot-dtb.img BINMAN .binman_stamp OFCHK .config make[1]: Leaving directory '/home/joe/MyTinkerboardFiles/u-boot/tinker-s-rk3288_output'
Similar to the Linux kernel, menuconfig
can be used to make changes to the configuration. This is optional; there is no real need to make any changes.
If the serial console employs old hardware or is "noisy," the u-boot serial console baud rate setting can be reduced. Newer systems default to 1500000 baud, but the tinker-s-rk3288_defconfig evidently sets its default at 115200. If this is still too fast, it can be changed to e.g. 9600.
user $
grep -i baudrate .config
CONFIG_BAUDRATE=115200
user $
make menuconfig
Get rkbin and create trust.img[3]
From u-boot directory, cd .. to move to the parent project directory, then get rkbin sources (peer level to the project's u-boot directory) --
user $
git clone https://github.com/rockchip-linux/rkbin.git
user $
cd rkbin/
user $
./tools/trust_merger RKTRUST/RK3399TRUST.ini
Create uboot.img
If not already there, cd to /path/to/rkbin, then --
user $
./tools/loaderimage --pack --uboot ../u-boot/tinker-s-rk3288_output/u-boot-dtb.bin uboot.img
pack input ../u-boot/tinker-s-rk3288_output/u-boot-dtb.bin pack file size: 553000(540 KB) crc = 0x746c261e uboot version: U-Boot 2017.09-gc64e256218-200416 #yzc (Apr 29 2020 - 16:22:05)
pack uboot.img success!Installing u-boot
When powered on, the TinkerBoard S will attempt to find a bootloader in the following order:
- Removable eMMC - empty connector, not populated by default on 4c Plus
- microSD card - i.e. this is the only real option for where to put u-boot
Note that if the maskrom/eMMC Recovery jumper header is set in the "default/disable/park" position, the board will try to boot from the eMMC; if it is set in the "eMMC Recovery/MASKROM" position, it will try to boot from the SD card.
Once U-Boot is loaded on one of these devices, it can then be used to load the kernel from MMC/SD or USB external storage, or via the network. (There is no M.2 nor PCIe connector on the TinkerBoard/TInkerBoard S. By default, after exhausting other options, u-boot will connect to the local network's dhpc server, looking for tftp service from which to retrieve a bootable image (this might be considered a security concern).
Installing on microSD/eMMC
If writing to the eMMC, connect the board (microUSB) connector to a PC (USB-A).
If writing to a micro SD Card, put the card in a card reader and connect that to a PC/workstation USB port.
Note the device connected, and as root, enter the u-boot build directory, and write the images to the card.
For miniloader boot option, the Rockchip community (http://opensource.rock-chips.com/wiki_Boot_option) instructs loading these files built above at the associated sectors of the eMMC/SD Card --
dd if=idbloader.img of=<device> seek=64 dd if=uboot.img of=<device> seek=16384 dd if=trust.img of=<device> seek=24576 dd if=boot.img of=<device> seek=32768 dd if=rootfs.img of=<device> seek=262144
However, it also notes that "boot.img" may also be the boot partition/folder of the rootfs, wherein the extlinux/extlinux.conf, zImage, and tinker-s-rk3288.dtb file will reside (with optional initrd and/or optional grub.efi. The example below assumes no initrd, no grub.efi, and will append the rootfs information to kernel cli, etc.
There are separate instructions at the link above for loading files pertaining to TPL/SPL boot option)* Note that
uboot.img
is written starting at sector 16384, trust.img is written at sector 24576, and the scenario expects the boot.img
(or the boot directory/partition) to be at sector 32768. Make sure your card is partitioned such that 32768 is the start address for the boot partition (FAT 32), and there is no other file system installed below that sector.
- Be sure to replace
/dev/sdd
with the correct device!
Write output files to boot media
root #
dmesg | tail ### note information about device just connected
root #
cd /path/to/u-boot/
root #
dd if=tinker-s-rk3288_output/idbloader.img of=/dev/sdd seek=64
140+0 records in 140+0 records out 71680 bytes (72 kB, 70 KiB) copied, 0.0350433 s, 2.0 MB/s
root #
cd ../rkbin/
root #
dd if=uboot.img of=/dev/sdd seek=16384
8192+0 records in 8192+0 records out 4194304 bytes (4.2 MB, 4.0 MiB) copied, 0.681352 s, 6.2 MB/s
root #
dd if=trust.img of=/dev/sdd seek=24576
8192+0 records in 8192+0 records out 4194304 bytes (4.2 MB, 4.0 MiB) copied, 0.683164 s, 6.1 MB/s