Skip to main content
Version: 6

Build U-Boot from Source Code

Introduction​

This article describes how to build the U-Boot without using a higher-level build system such as the Yocto Project/OpenEmbedded. This procedure mostly makes sense during bootloader development.

We provide OpenEmbedded recipes that build U-Boot and Linux as part of a complete BSP image; hence if you plan to build a full BSP image, follow the Build a Reference Image with Yocto Project/OpenEmbedded article.

The U-Boot bootloader's source code is available on our Git server at git.toradex.com.

This is the first article of a three-part series about building from source code. Check the following articles if you are looking for information about:

Prerequisites​

Prepare the Host Machine for Cross-Compilation​

Use version 9.2 of the Arm releases binary toolchains to cross-compile software for Toradex modules:

  • For 32 bit Arm: gcc-arm-9.2-2019.12-x86_64-arm-none-linux-gnueabihf.tar.xz
  • For 64 bit Arm: gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu.tar.xz

You have to choose to download either the 32 bit or 64 bit Arm cross-toolchain, according to the architecture of your Computer on Module SoC. Select the correct one from the tabs below:

To install the toolchain on your host machine, download and unpack the tar.xz file. From the command-line:

$ cd ~
$ wget -O gcc-arm-9.2-2019.12-x86_64-arm-none-linux-gnueabihf.tar.xz "https://developer.arm.com/-/media/Files/downloads/gnu-a/9.2-2019.12/binrel/gcc-arm-9.2-2019.12-x86_64-arm-none-linux-gnueabihf.tar.xz?revision=fed31ee5-2ed7-40c8-9e0e-474299a3c4ac&la=en&hash=76DAF56606E7CB66CC5B5B33D8FB90D9F24C9D20"
$ tar xvf gcc-arm-9.2-2019.12-x86_64-arm-none-linux-gnueabihf.tar.xz
$ ln -s gcc-arm-9.2-2019.12-x86_64-arm-none-linux-gnueabihf gcc-linaro

Or you can download the toolchain from Arm website.

The U-Boot and Linux makefiles use the environment variables ARCH/CROSS_COMPILE to configure and call the compiler correctly. Therefore, these environment variables must be exported in any shell instance that will run configure/compile commands to build U-Boot or Linux for the target module.

$ export ARCH=arm
$ export DTC_FLAGS="-@"
$ export PATH=~/gcc-linaro/bin/:$PATH
$ export CROSS_COMPILE=arm-none-linux-gnueabihf-

You can put those commands into a file and source that file to export it more easily, e.g.:

$ echo "export ARCH=arm" >> ~/export_compiler
$ echo "export DTC_FLAGS='-@'" >> ~/export_compiler
$ echo "export PATH=~/gcc-linaro/bin/:$PATH" >> ~/export_compiler
$ echo "export CROSS_COMPILE=arm-none-linux-gnueabihf-" >> ~/export_compiler
$ source ~/export_compiler

Install Tools and Dependencies​

Device Tree Compiler (DTC) Tool​

U-Boot and the device tree overlays compilation for some modules needs a device tree compiler (DTC). We recommend DTC version 1.6.0 or higher.

You can build the latest version (DTC 1.6.0 at the time of writing) from the source:

$ git clone git://git.kernel.org/pub/scm/utils/dtc/dtc.git -b v1.6.0 ~/dtc
$ cd ~/dtc
$ make
$ export PATH=$HOME/dtc/:$PATH
info

On Fedora and on Ubuntu 22.04, there have been reported DTC build errors libfdt/libfdt.h:251:28: warning: array subscript β€˜struct fdt_header[0]’ is partly outside array bounds of β€˜unsigned char[4]’ [-Warray-bounds].
To disable treating errors as warnings, you can remove the flag -Werror from the CFLAGS on the Makefile.
We have not evaluated the consequences of doing it, do it at your own risk!

U-Boot Tools​

The uImage target of the Linux kernel compilation needs a recent mkimage tool.

One can install the Fedora package uboot-tools:

$ sudo dnf install uboot-tools

Or with the corresponding Debian/Ubuntu package u-boot-tools:

$ sudo apt-get install u-boot-tools

Alternatively, mkimage tool is also built during the U-Boot compilation. You can follow the U-Boot building instructions as explained further in this article, and after that, include it in PATH.

U-boot Version Information​

The required git branch, U-Boot configuration, and U-Boot/Linux binaries to be used depend on module type and BSP version, as we will explain in this article.

For a high-level overview of the BSP Versions, check out our Embedded Linux Release Matrix. There you will find the version information of the Linux kernel, U-Boot, Yocto/OpenEmbedded, the Toradex BSP, and Linux images, along with release dates.

SoCU-Boot Git BranchU-Boot ConfigurationU-Boot Binary
i.MX 8/8X/8MM/8MPtoradex_imx_lf_v2022.04<family>-<SoC>_defconfig8/8X: u-boot.bin
8MM/8MP: u-boot.bin & u-boot-spl.bin
i.MX 7v2022.07colibri_imx7_defconfig
colibri_imx7_emmc_defconfig
u-boot-nand.imx
u-boot.imx
i.MX 6v2022.07<family>_<SoC>_defconfigu-boot.img
i.MX 6ULLv2022.07colibri-imx6ull_defconfig
colibri-imx6ull-emmc_defconfig
u-boot-nand.imx
u-boot.imx

For i.MX 8/8X/8MM/8MP and i.MX 6 based modules, you might replace:

  1. <family>: colibri, apalis or verdin
  2. <SoC>: imx6, imx8, imx8x, imx8mm or imx8mp

Building U-Boot​

info

In the following instructions, you will be directed to create a directory called ~/workdir to store all the source and build files. You can, of course, replace this directory name with any other name you prefer.

Source​

Obtain the U-Boot source code using Git:

$ mkdir -p ~/workdir
$ cd ~/workdir
$ git clone -b <branch> git://git.toradex.com/u-boot-toradex.git

Replace <branch> by the U-Boot Git Branch for your specific configuration. Check the section U-boot Version for this specific information.

info

Should your company firewall/gateway inhibit the git protocol, you may use HTTP or HTTPS instead (e.g. git clone https://git.toradex.com/u-boot-toradex.git).

Configuration​

Ensure the environment is configured for cross-compilation as explained in the toolchain chapter. Then choose one of those configurations and load it:

$ cd ~/workdir/u-boot-toradex
$ make <config>
info

Replace <config> by the U-Boot Configuration for your specific configuration. Check the section U-boot Version for this specific information.

Compilation​

The following is the procedure to compile the boot loader.

$ make -j$(nproc) 2>&1 | tee build.log
$ ls u-boot.bin
info

Starting with BSP 3, we use U-Boot based on 2019.07 which changed certain make targets to include -dtb in their names. If you need backward compatibility with older BSPs, make sure you explicitly state the make target e.g., as follows: make u-boot.imx. Otherwise, the new target named u-boot-dtb.imx will be built. However, the two are equal apart from their name.

The resulting U-boot binary will be a file with the name u-boot.bin.

U-Boot Compilation Troubleshoot​

Click below to see info for U-Boot some common issues when building U-Boot.

Cannot find -lgcc

When using the cross compiler built by an OpenEmbedded build of our BSP V2.5 or later, the compiler might have an error during linking

arm-angstrom-linux-gnueabi-ld.bfd: cannot find -lgcc
make[2]: *** [examples/standalone/hello_world] Error 1
make[1]: *** [examples/standalone] Error 2
make: *** [examples] Error 2

The new cross compiler does not have a hard-coded default sysroot and hence needs the sysroot to be specified explicitly:

$ make CC='arm-angstrom-linux-gnueabi-gcc --sysroot=${HOME}/oe-core/build/out-glibc/sysroots/colibri-vf'

Additional Mandatory Steps: Boot Container​

Some SoCs will require additional steps to build the components necessary for the boot. Check on the tabs below each steps that refer to your specific SoC. If you are targetting a different SoC, you can skip this session.

The NXP i.MX 8QuadMax / i.MX 8QuadXPlus boots using a Cortex-M4 boot CPU called System Controller Unit (SCU). The SCU firmware (SCFW) is in large part provided by NXP, but Toradex has slightly altered it for the Apalis iMX8/Apalis iMX8X and Colibri iMX8X. The firmware also loads an intermediate firmware running on the Cortex-A class CPUs: The ARM trusted firmware (ATF). The ARM trusted firmware then hands over control to U-Boot, which then can boot Linux.

To learn more about SCFW, see the Build Custom i.MX 8/8X System Controller Firmware (SCFW) article.

The DDR memory timings, the SCU firmware, the ATF and U-Boot, and any potential Cortex-M4 auxiliary firmware are all stored in a single boot container. This boot container is read by the boot ROM from the boot device, starting at a specific offset (33kB for V1.0A modules booting from SD cards).

Follow the steps described in the sections below in the specific order.

  1. Obtaining the Security Controller (SECO) Firmware
  2. Build the SCU Formware (SCFW)
  3. Build the ARM trusted firmware (ATF/TF-A)
  4. Assemble the Boot Container

Obtain the DDR Training Firmware​

SoCNXP BSP VersionNXP i.MX Firmware File Name
i.MX 8MM/8MPL5.15.32_2.0.0firmware-imx-8.17.bin

E.g. use wget for download, and extract the firmware, for example:

$ cd ~/workdir
$ wget https://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-imx-8.17.bin
$ chmod u+x firmware-imx-8.17.bin
$ ./firmware-imx-8.17.bin
$ ls firmware-imx-8.17/firmware/ddr/synopsys/

NXP provides the DDR training firmware in binary form. You will need to accept the NXP License Agreement as part of the unpacking process.

  • lpddr4_pmu_train_1d_dmem.bin
  • lpddr4_pmu_train_2d_dmem.bin
  • lpddr4_pmu_train_1d_imem.bin
  • lpddr4_pmu_train_2d_imem.bin

Obtaining the Security Controller (SECO) Firmware​

BSP VersionNXP BSP VersionNXP Firmware File NameNXP Firmware Path
6.0.0L5.15.32_2.0.0imx-seco-3.8.6.binimx-seco-3.8.6/firmware/seco/<SoC>-ahab-container.img
6.1.0L5.15.52_2.1.0imx-seco_5.8.7.1.binimx-seco-5.8.7.1/firmware/seco/<SoC>-ahab-container.img

Replace <SoC> for one of the following:

  • Apalis iMX8: mx8qmb0
  • Colibri iMX8X V1.0B and earlier: mx8qxb0
  • Colibri iMX8X V1.0C and later: mx8qxc0

You can use wget for download, and extract the firmware. For example:

$ cd ~/workdir
$ wget -c https://www.nxp.com/lgfiles/NMG/MAD/YOCTO/imx-seco-5.8.7.bin
$ chmod u+x imx-seco-3.8.6.bin
$ ./imx-seco-5.8.7.bin
$ ls imx-seco-5.8.7/firmware/seco/
info

NXP provides the SECO firmware in binary form. You will need to accept the NXP End-User License Agreement (EULA) as part of the unpacking process.

Build the SCU Firmware (SCFW)​

The SCU firmwares for Apalis iMX8/Apalis iMX8X and Colibri iMX8X are available in our i.MX-System-Controller-Firmware GitHub repository.

BSP VersionNXP BSP VersionSCFW Version
6.0.0L5.15.32_2.0.01.14.0
6.1.0L5.15.52_2.1.01.14.0
info

Toradex customers rarely need to rebuild SCFW. Therefore, in the following instructions, we will show how you can download the SCFW firmware. If you, for any reason, need to customize SCFW, see the Build Custom i.MX 8/8X System Controller Firmware (SCFW) article.

You can use clone the SFCW repository from Toradex Github:

$ mkdir -p ~/workdir/scfw-bin && cd ~/workdir/scfw-bin
$ git clone https://github.com/toradex/i.MX-System-Controller-Firmware.git
$ mv ./i.MX-System-Controller-Firmware/src/scfw_export_<mx8qm-or-mx8qx>_b0/build_<mx8qm-or-mx8qx>_b0/mx8qm-apalis-scfw-tcm.bin ./scfw_tcm.bin

If you need, you can use wget to download an specific version. For example:

$ wget https://github.com/toradex/i.MX-System-Controller-Firmware/raw/d8d7320aec228cd73c4512a92d55c900786873e0/src/scfw_export_mx8qx_b0/build_mx8qx_b0/mx8qx-colibri-scfw-tcm.bin

The file scfw_tcm.bin is necessary for the final container.

Build the ARM trusted firmware (ATF/TF-A)​

For the i.MX 8/8X and i.MX 8MM/8MP based modules, the ATF/TF-A Branch is lf_v2.6 and the binary is always the following form:

  • build/<Platform>/release/bl31.bin

Replace <Platform> by the one of the platforms indicated below.

  • Apalis iMX8: imx8qm
  • Colibri iMX8X: imx8qx
  • Verdin iMX8M Mini: imx8mm
  • Verdin iMX8M Plus: imx8mp

On top of it, OpenEmbedded applies two patches, necessary for the system to behave as expected:

The patches can be found at: files Β» imx-atf Β» recipes-bsp - meta-toradex-nxp.git and you can apply them manually using git am or git apply.

ATF / TF-A can be obtained from NXP git servers:

$ cd ~/workdir
$ git clone https://github.com/nxp-imx/imx-atf.git -b lf_v2.6
info

If your company firewall/gateway inhibit the git protocol, you may use HTTP or HTTPS instead.

Currently, there are no changes necessary for ARM Trusted Firmware. To be able to build the ATF firmware, first you'll need to download and setup the GNU Toolchain for Hard Float Calling Convention. When the toolchain is installed and you have the CROSS_COMPILE, ARCH and PATH correctly pointing to it, you can proceed to build the firmware directly:

$ cd imx-atf
$ make PLAT=<Platform> bl31

The resulting binary file bl31.bin created in build/<Platform>/release/ is necessary for the final container.

Assemble the Boot Container​

Finally, to assembly the boot container, you need to obtain the imx-mkimage utility.

SoCBranch
i.MX 8/8xlf-5.15.32_2.0.0
i.MX 8MM/8MPlf-5.15.32_2.0.0

Git clone it from the repository:

$ cd ~/workdir
$ git clone -b <Branch> https://source.codeaurora.org/external/imx/imx-mkimage/

Replace <Branch> by the Branch for your specific configuration as indicated in the above table.

caution

The binary u-boot.bin is necessary for the final boot container. Make sure you followed the previous instructions on how to build U-Boot.

Copy all the binaries to the corresponding SoC directory inside imx-mkimage. For Apalis iMX8QM, for example

$ cp ~/workdir/scfw-bin/scfw_tcm.bin iMX8QM
$ cp ~/workdir/imx-atf/build/imx8qm/release/bl31.bin iMX8QM
$ cp ~/workdir/u-boot-toradex/u-boot.bin iMX8QM
$ cp ~/workdir/imx-seco-3.7.4/firmware/seco/<SECO Firmware File> iMX8QM

Finally, use make to build the boot container. For Apalis iMX8QM:

$ make SOC=iMX8QM flash_b0
$ ls iMX8QM/flash.bin

And for Colibri iMX8QX:

$ make REV=C0 SOC=iMX8QX flash
$ ls iMX8QX/flash.bin

Replace <SECO Firmware File> by the SECO Firmware File for your specific configuration as indicated before and rename the file flash.bin to imx-boot so it will be suitable for a Toradex Easy Installer Image. Make sure to remove REV=C0 if you are building for B0 or older silicon versions.

$ mv iMX8<QM-or-QX>/flash.bin iMX8QM/imx-boot

Deploying the U-Boot binary to an Image​

To deploy your custom U-Boot binary to an image, follow the steps described bellow:

  1. Start from a Existing Sample Image: Download and extract one of the Toradex prebuild images. Choose the appropriate image for your SoM in the Reference Images for Yocto Project Software Downloads
  2. Integrate Artifacts: Integrate the U-Boot artifacts into our regular Toradex Easy Installer package: Replace the U-Boot binary and, if applicable, the SPL in the unpacked Toradex Easy Installer directory.
  3. Adjust Image.json: Now adjust the image.json to your liking (e.g., change the name and description for you to distinguish it from the original package). You may, of course, also change any of the other properties as documented in the Toradex Easy Installer article on our developer website.
  4. Deploy the Toradex Easy Installer Image: You may now use the above prepared Toradex Easy Installer package with the Toradex Easy Installer.

U-Boot: Standalone Application​

info

If you don't know if you need to read this, you will not need to read this.

U-Boot allows one to run standalone applications which may use callbacks into the U-Boot binary. One has to overcome some obstacles to get the hello_world example in the U-Boot sources up and running on an Arm-based CPU.

Details

1) The binary needs to be linked to an address where it eventually gets loaded and executed. I.e., set CONFIG_STANDALONE_LOAD_ADDR to your chosen address.

2) U-Boot and the standalone application must be compiled for the same ARM instruction set (arm vs. thumb) if you build both binaries from the same configured U-Boot tree that is inherently so.

3) If the binaries are built for thumb then one has to set the LSB in the address given to the go command. E.g. if the entry point is 0x12000000, then one has to start with 'go 12000001'.

Example for Colibri iMX6:

Link the standalone binary to 0x11000000 and build it as follows:

$ make CONFIG_STANDALONE_LOAD_ADDR=0x11000000 -j$(nproc)

Copy the resulting binary file to an SD card

$ cp examples/standalone/hello_world.bin <path to SD card>/

In U-Boot, load the binary to RAM and execute it. Note that for some time, we compile using the thumb instruction set.

> load mmc 1:1 0x11000000 hello_world.bin
reading hello_world.bin
578 bytes read in 14 ms (40 KiB/s)

> go 0x11000001 Hello World!
## Starting application at 0x11000001 ...
Example expects ABI version 9
Actual U-Boot ABI version 9
Hello World
argc = 3
argv[0] = "0x11000001"
argv[1] = "Hello"
argv[2] = "World!"
argv[3] = "<NULL>"
Hit any key to exit ...

## Application terminated, rc = 0x0
Send Feedback!