3.1.1.1. General Information
Install host dependencies
To install host dependencies for building TI U-boot source (standalone) on Ubuntu 22.04+, run the following command in the terminal prompt:
sudo apt install git xz-utils build-essential autoconf flex bison libssl-dev bc libncurses-dev \
python3 python3-setuptools python3-dev python3-yaml python3-jsonschema python3-pyelftools \
swig yamllint libgnutls28-dev
Note
The recommended host machine for building U-Boot is Ubuntu 22.04. Users of Ubuntu 18.04 may need to install Python 3.7 or higher. If using the default Python 3.6 that comes with Ubuntu 18.04, users may need to install these additional dependencies:
pip install dataclasses pyelftools jsonschema yamllint importlib-resources
3.1.1.1. Getting the BL-1 Source Code
AM62L devices use TF-A BL-1 boot loader to configure LPDDR4 to
enable secondary program loader.
The easiest way to get access to the BL-1 source code is by
downloading and installing the Processor SDK Linux. Once installed,
the BL-1 source code is included in the SDK at the path <path to tisdk>/board-support
.
For your convenience the sources also includes the BL-1’s
git repository including commit history.
Alternatively, BL-1 sources can directly be fetched from GIThub. The GIT repo URL, branch and commit id can be found in the U-Boot section of the release notes.
3.1.1.1. Build BL-1
Note
The following commands are intended to be run from the root of the TF-A tree unless otherwise specified. The root of the TF-A tree is the top-level directory and can be identified by looking for the “licenses” directory.
Setting up the toolchain paths
Before compiling any of the sources referenced in this document, set the cross compiler paths to the toolchains packaged in the Processor SDK [Recommended] as shown below. Refer to Yocto-built SDK Toolchains section for more details on usage.
host# export CROSS_COMPILE_64="${SDK_INSTALL_DIR}/linux-devkit/sysroots/x86_64-arago-linux/usr/bin/aarch64-oe-linux/aarch64-oe-linux-"
host# export SYSROOT_64="${SDK_INSTALL_DIR}/linux-devkit/sysroots/aarch64-oe-linux"
host# export CC_64="${CROSS_COMPILE_64}gcc --sysroot=${SYSROOT_64}"
host# export CROSS_COMPILE_32="${SDK_INSTALL_DIR}/k3r5-devkit/sysroots/x86_64-arago-linux/usr/bin/arm-oe-eabi/arm-oe-eabi-"
If the Processor SDK is not installed, the Arm GNU toolchains can be downloaded and setup. Refer to ARM toolchains section for more details on usage.
$ cd <path to tf-a dir>
$ make CROSS_COMPILE="$CROSS_COMPILE_64" ARCH=aarch64 PLAT=k3 TARGET_BOARD=am62l am62l_bl1
<or to build bl-1 and bl-31 binaries from TF-A repo>
$ make CROSS_COMPILE="$CROSS_COMPILE_64" ARCH=aarch64 PLAT=k3 TARGET_BOARD=am62l
3.1.1.1.1. Getting the U-Boot Source Code
The easiest way to get access to the U-boot source code is by
downloading and installing the Processor SDK Linux. Once installed,
the U-Boot source code is included in the SDK at the path <path to tisdk>/board-support
.
For your convenience the sources also includes the U-Boot’s
git repository including commit history.
Alternatively, U-Boot sources can directly be fetched from GIT. The GIT repo URL, branch and commit id can be found in the U-Boot section of the release notes.
3.1.1.1.2. Build U-Boot
Note
The following commands are intended to be run from the root of the U-Boot tree unless otherwise specified. The root of the U-Boot tree is the top-level directory and can be identified by looking for the “MAINTAINERS” file.
Prebuilt Images
Several prebuilt images are required from the TI Processor SDK for building U-Boot on K3 based platforms.
TF-A (BL-1 and BL-31): Refer to ARM Trusted Firmware-A for more information
ti-linux-firmware (BINMAN_INDIRS): Prebuilt TIFS binaries are available in ti-linux-firmware.
All of these are available in the SDK at <path to tisdk>/board-support/prebuilt-images>
Go here to download and install the SDK.
Setting up the toolchain paths
Before compiling any of the sources referenced in this document, set the cross compiler paths to the toolchains packaged in the Processor SDK [Recommended] as shown below. Refer to Yocto-built SDK Toolchains section for more details on usage.
host# export CROSS_COMPILE_64="${SDK_INSTALL_DIR}/linux-devkit/sysroots/x86_64-arago-linux/usr/bin/aarch64-oe-linux/aarch64-oe-linux-"
host# export SYSROOT_64="${SDK_INSTALL_DIR}/linux-devkit/sysroots/aarch64-oe-linux"
host# export CC_64="${CROSS_COMPILE_64}gcc --sysroot=${SYSROOT_64}"
host# export CROSS_COMPILE_32="${SDK_INSTALL_DIR}/k3r5-devkit/sysroots/x86_64-arago-linux/usr/bin/arm-oe-eabi/arm-oe-eabi-"
If the Processor SDK is not installed, the Arm GNU toolchains can be downloaded and setup. Refer to ARM toolchains section for more details on usage.
Board |
SD/eMMC UART OSPI USB-DFU USB-MSC |
---|---|
AM62LX EVM |
am62lx_evm_defconfig |
Note
Where to get the sources:
ti-u-boot version: U-Boot
ti-linux-firmware version: ti-linux-firmware
TF-A version: TF-A
$ export UBOOT_DIR=<path-to-ti-u-boot>
$ export TI_LINUX_FW_DIR=<path-to-ti-linux-firmware>
$ export TFA_DIR=<path-to-arm-trusted-firmware>
Note
The instructions below assume all binaries are built manually. For instructions to build :file:bl1.bin or :file:bl31.bin go to: ARM Trusted Firmware-A.
BINMAN_INDIRS can point to
<path-to-tisdk>/board-support/prebuilt-images
to use
the pre-built binaries that come in the pre-built SDK.
$ make CROSS_COMPILE="$CROSS_COMPILE_64" am62lx_evm_defconfig O=$UBOOT_DIR/out
$ make CROSS_COMPILE="$CROSS_COMPILE_64" O=$UBOOT_DIR/out \
BL1=$TFA_DIR/build/k3/am62l/release/bl1.bin \
BL31=$TFA_DIR/build/k3/am62l/release/bl31.bin \
BINMAN_INDIRS=$TI_LINUX_FW_DIR
Note
BINMAN_INDIRS is used to fetch the TIFS binaries from
<path to ti-linux-firmware>/ti-sysfw/
. If using the SDK,
BINMAN_INDIRS can point to
<path to SDK>/board-support/prebuilt-images
. Else any
folder where SYSFW binaries are present in
<path to folder>/ti-sysfw/
can be used. Please make sure
to use the absolute path.
Target Images
Copy the below images to the boot partition of an SD card and boot. Instructions to format the SD card can be found here.
HS-FS
tiboot3-am62lx-hs-fs-evm.bin
tispl.bin
u-boot.img
Warning
Rename tiboot3-<board>-evm.bin
to tiboot3.bin
in order for the device to load this binary from the SD card boot partition.
Also, (For GP devices only) rename tispl.bin_unsigned
to tispl.bin
and u-boot.img_unsigned
to u-boot.img
as well.
3.1.1.1.3. Image Formats
tiboot3.bin
TIBOOT3 ┌─────────────┐ │ X.509 │ │ Certificate │ │┌───────────┐│ ││ BL-1 ││ │├───────────┤│ ││ TIFS ││ │├───────────┤│ ││ TIFS CERT ││ │└───────────┘│ └─────────────┘
tispl.bin
TISPL ┌─────────────┐ │ X.509 │ │ Certificate │ │┌───────────┐│ ││ BL-31 ││ │├───────────┤│ ││ TIFS ││ │├───────────┤│ ││ TIFS CERT ││ │├───────────┤│ ││ BRD + SEC ││ ││ CONFIGS ││ │├───────────┤│ ││ U-BOOT ││ ││ SPL ││ │└───────────┘│ └─────────────┘
3.1.1.1.4. Boot Flow
Unlike with most other K3 SoCs, the AM62LX does not have an Cortext-R5 MCU core which ROM uses to initialize the SoC. Therefore it uses a 2 phase ROM boot. The first phase will load the tiboot3.bin image which contains Trusted-Firmware-A’s BL-1 loader along with the typical X.509 certificate to authenticate and validate the image which is used to intialize the console and DDR for the next phase.
┌───────────────────┐┌───────────────────┐
│ Secure ROM ││ Public ROM │
│ SMS (M4) ││ (Cortex-A53) │
│ ││ │
│┌─────────────────┐││ │
││ Reset Release │││ │
│└────────┬────────┘││ │
│ │ ││ │
│┌────────▼────────┐││ │
││ ROM Init │││ │
│└────────┬────────┘││ │
│ │ ││ │
│┌────────▼────────┐││┌─────────────────┐│
││ Release A53 ┼┼┼► Release A53 ││
│└─────────────────┘││└────────┬────────┘│
│ ││ │ │
│ Validate Image ││┌────────▼────────┐│
│┌─────────────────┐│││ ROM Init ││
││ Integrity Check ◄┼┼┼ (1st Phase) ││
│├─────────────────│││└────────┬────────┘│
││ Authentication │││ │ │
│├─────────────────┤││┌────────▼────────┐│
││ Decryption ││││ WFI ││
│└────────┬────────┘││└─────────────────┘│
│ │ ││ │
│┌────────▼────────┐││ End of ROM │
││ Wait for WFI │││~~~~~~~~~~~~~~~~~~~│
││ on Cortex-A53 │││ Start of │
│└────────┬────────┘││ BL-1 │
│ │ ││ │
│┌────────▼────────┐││┌─────────────────┐│
││ Start BL-1 ┼┼┼► DDR Init ││
│└────────┬────────┘││└────────┬────────┘│
│ │ ││ │ │
│┌────────▼────────┐││┌────────▼────────┐│
││ Wait for BL-1 ◄┼┼┼ Send BL-1 Done ││
││ Done Msg │││└────────┬────────┘│
│└─────────────────┘││ │ │
│ ││┌────────▼────────┐│
│ │││ WFI ││
│ ││└─────────────────┘│
└───────────────────┘└───────────────────┘
After the BL-1 sends a message back to the Secure ROM to indicate it has completed, the Secure ROM will reset the A53 back into Public ROM to begin the 2nd ROM boot phase to load the tispl.bin into the SoC.
┌───────────────────┐┌───────────────────┐
│ Secure ROM ││ Public ROM │
│ SMS (M4) ││ (Cortex-A53) │
│ ││ │
│┌─────────────────┐││ │
││ Program Reset │││┌─────────────────┐│
││ Vector And ┼┼┼► Release A53 ││
││ Reset A53 │││└────────┬────────┘│
│└─────────────────┘││ │ │
│ ││ │ │
│ Validate Image ││┌────────▼────────┐│
│┌─────────────────┐│││ ROM Init ││
││ Integrity Check ◄┼┼┼ (2nd Phase) ││
│├─────────────────┤││└────────┬────────┘│
││ Authentication │││ │ │
│├─────────────────┤││┌────────▼────────┐│
││ Decryption ││││ WFI ││
│└────────┬────────┘││└─────────────────┘│
│ │ ││ │
│┌────────▼────────┐││ End of ROM │
││ Wait for WFI │││~~~~~~~~~~~~~~~~~~~│
││ on Cortex-A53 │││ │
│└────────┬────────┘││ │
│ │ ││ │
│┌────────▼────────┐││ │
││ Program Reset │││┌─────────────────┐│
││ Vector And ┼┼┼► TF-A (BL-31) ││
││ Reset A53 │││└────────┬────────┘│
│└────────┬────────┘││ │ │
│ │ ││┌────────▼────────┐│
│┌────────▼────────┐│││ U-Boot SPL ││
││ Prep M4 Reset │││└────────┬────────┘│
│└────────┬────────┘││ │ │
│ │ ││┌────────▼────────┐│
│┌────────▼────────┐│││ U-Boot ││
││ Boot TI-FS │││└────────┬────────┘│
│└────────┬────────┘││ │ │
│ │ ││ │ │
│ End of ROM ││ │ │
│~~~~~~~~~~~~~~~~~~~││ │ │
│ │ ││┌────────▼────────┐│
│┌────────▼────────┐│││ ││
││ ││││ ││
││ TI-FS ││││ Linux ││
└┴─────────────────┴┘└┴─────────────────┴┘
From there TIFS, TF-A and U-Boot will has completed their initialization routines which can begin loading the operating system and complete the boot process.
3.1.1.1.5. U-Boot Environment
Note
SDK 9.0 will not default to the environments that are saved on the boards, It will default to the ones that are given with the particular uboot in the release.
By default the SDK builds will have the default environments whenever being run, to have some custom environments, one needs to rely on uEnv.txt file.
The added benefit of using uEnv.txt is that it is more granular than the saveenv counterpart as we can choose to store the variables that are actually being set during the development workflow.
Writing to MMC/EMMC
=> env export -t $loadaddr <list of variables>
=> fatwrite mmc ${mmcdev} ${loadaddr} ${bootenvfile} ${filesize}
The following will update the uEnv.txt file on the bootmedia and then whenever “run envboot” is run on the board, uEnv.txt will be read based on mmcdev value to be read either from emmc/sd card.
You can specifically choose the variables that you are changing in your development process so that the other variables are not affected due to the whole environment being saved. Optionally, one can save the full environment too in uEnv.txt by not specifying <list of variables> this will have some issues with the ethernet mac addresses not being overridden but other things will be set.
Reading from MMC/EMMC
By default run envboot will read it from the MMC/EMMC partition ( based on mmcdev) and set the environments.
If manually needs to be done then the environment can be read from the filesystem and then imported
=> fatload mmc ${mmcdev} ${loadaddr} ${bootenvfile}
=> env import -t ${loadaddr} ${filesize}
For production environments if one needs to rely on saveenv counterpart then they can always refer to the commit
Networking Environment
When using a USB-Ethernet dongle a valid MAC address must be set in the environment. To create a valid address please read **this page**. Then issue the following command:
=> setenv usbethaddr value:from:link:above
You can use the printenv command to see if usbethaddr is already set.
Then start the USB subsystem:
=> usb start
The default behavior of U-Boot is to utilize all information that a DHCP server passes to us when the user issues the dhcp command. This will include the dhcp parameter next-server which indicates where to fetch files from via TFTP. There may be times however where the dhcp server on your network provides incorrect information and you are unable to modify the server. In this case the following steps can be helpful:
=> setenv autoload no
=> dhcp
=> setenv serverip correct.server.ip
=> tftp
Another alternative is to utilize the full syntax of the tftp command:
=> setenv autoload no
=> dhcp
=> tftp ${loadaddr} server.ip:fileName
3.1.1.1.6. Available RAM for image download
To know the amount of RAM available for downloading images or for other
usage, use bdinfo
command.
=> bdinfo
arch_number = 0x00000000
boot_params = 0x80000100
DRAM bank = 0x00000000
-> start = 0x80000000
-> size = 0x7F000000
baudrate = 115200 bps
TLB addr = 0xFEFF0000
relocaddr = 0xFEF30000
reloc off = 0x7E730000
irq_sp = 0xFCEF8880
sp start = 0xFCEF8870
Early malloc usage: 890 / 2000
After booting, U-Boot relocates itself (along with its various reserved
RAM areas) and places itself at end of available RAM (starting at
relocaddr
in bdinfo
output above). Only the stack is located
just before that area. The address of top of the stack is in
sp start
in bdinfo
output and it grows downwards. Users should
reserve at least about 1MB for stack, so in the example output above,
RAM in the range of [0x80000000, 0xFCE00000]
is safely available for
use.
3.1.1.1.7. Device Trees
A note about device trees. Now all supported boards are required to use a device tree to boot. To facilitate this in supported platforms, a command in U-Boot environment findfdt is available that will set the fdtfile variable to the name of the device tree to use, as found with the kernel sources. In the Keystone-2 family devices (K2H/K/E/L/G), it is specified by name_fdt variable for each platform. The device tree is expected to be loaded from the same media as the kernel, and from the same relative path.
3.1.1.1.8. SRAM memory Layout during initial bootloader stage
The SRAM memory layout explains the memory used for Bootloader’s operation.
┌────────────────────┐ 0x7081_8000 ┬ │ Debug Buffers │ │ ├────────────────────┤ 0x7081_6000 │ │ TIFS -> A53 IPC │ │ ├────────────────────┤ 0x7081_5000 │ │ A53 -> TIFS IPC │ │ ├────────────────────┤ 0x7081_4000 │ │ │ │ │ *Free Space* │ │ │ │ │ ├────────────────────┤ 0x7081_0000 ┬ │ │ Translation Table │ │ │ ├────────────────────┤ 0x7080_D000 │ │ │ BSS │ │ │ MSRAM (96k) ├────────────────────┤ 0x7080_B9C0 │ │ │ Stack │ │ │ ├────────────────────┤ 0x7080_B1C0 │ BL-1 │ │ Data │ │ │ ├────────────────────┤ 0x7080_B000 │ │ │ RO-Data │ │ │ ├────────────────────┤ 0x7080_6000 │ │ │ Code │ │ │ ├────────────────────┤ 0x7080_0000 ┘ ─┤ │ │ │ │ ROM Data │ │ PSRAM (64k) │ │ │ └────────────────────┘ 0x707F_0000 ┴