3.1.1.1. General Information

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’s board-support directory. 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.

We strongly recommend the use of separate object directories when building. This is done with O= parameter to make. We also recommend that you use an output directory name that is identical to the configuration target name. That way if you are working with multiple configuration targets it is very easy to know which folder contains the u-boot binaries that you are interested in.

Setting the tool chain path

We strongly recommend using the toolchain that came with the Linux Core release that corresponds to this U-Boot release. For e.g:

export PATH=$HOME/<TOOLCHAIN_PATH>/bin:$PATH

Cleaning the Sources

If you did not use a separate object directory:

$ make CROSS_COMPILE=arm-none-linux-gnueabihf- distclean

If you used ‘O=am335x_evm’ as your object directory:

$ rm -rf ./am335x_evm

Compiling MLO and u-boot

Building of both u-boot and SPL is done at the same time. You must however first configure the build for the board you are working with. Use the following table to determine what defconfig to use to configure with:

Board

SD Boot

eMMC Boot

NAND Boot

UART Boot

Ethernet Boot

USB Ethernet Boot

USB Host Boot

SPI Boot

AM335x GP EVM

am335x_evm_defconfig

am335x_evm_defconfig

am335x_evm_defconfig

am335x_evm_defconfig

am335x_evm_defconfig

AM335x EVM-SK

am335x_evm_defconfig

am335x_evm_defconfig

am335x_evm_defconfig

AM335x ICE

am335x_evm_defconfig

am335x_evm_defconfig

BeagleBone Black

am335x_evm_defconfig

am335x_evm_defconfig

am335x_evm_defconfig

BeagleBone White

am335x_evm_defconfig

am335x_evm_defconfig

AM437x GP EVM

am43xx_evm_defconfig

am43xx_evm_defconfig

am43xx_evm_defconfig

am43xx_evm_defconfig

am43xx_evm_defconfig

am43xx_evm_usbhost_boot_defconfig

AM437x EVM-Sk

am43xx_evm_defconfig

am43xx_evm_usbhost_boot_defconfig

AM437x IDK

am43xx_evm_defconfig

am43xx_evm_qspiboot_defconfig (XIP)

AM437x ePOS EVM

am43xx_evm_defconfig

am43xx_evm_defconfig

am43xx_evm_usbhost_boot_defconfig

AM572x GP EVM

am57xx_evm_defconfig

am57xx_evm_defconfig

AM572x IDK

am57xx_evm_defconfig

AM571x IDK

am57xx_evm_defconfig

DRA74x/DRA72x/DRA71x EVM

dra7xx_evm_defconfig

dra7xx_evm_defconfig

dra7xx_evm_defconfig (DRA71x EVM only)

dra7xx_evm_defconfig(QSPI)

K2HK EVM

k2hk_evm_defconfig

k2hk_evm_defconfig

k2hk_evm_defconfig

k2hk_evm_defconfig

K2L EVM

k2l_evm_defconfig

k2l_evm_defconfig

k2l_evm_defconfig

K2E EVM

k2e_evm_defconfig

k2e_evm_defconfig

k2e_evm_defconfig

K2G GP EVM

k2g_evm_defconfig

k2g_evm_defconfig

k2g_evm_defconfig

k2g_evm_defconfig

K2G ICE

k2g_evm_defconfig

OMAP-L138 LCDK

omapl138_lcdk_defconfig

omapl138_lcdk_defconfig

Then (Use ‘am335x_evm’ and ‘AM335x GP EVM’ in this example):

$ make CROSS_COMPILE=arm-none-linux-gnueabihf- O=am335x_evm am335x_evm_defconfig
$ make CROSS_COMPILE=arm-none-linux-gnueabihf- O=am335x_evm

Note

Not all possible build targets for a given platform are listed here as the community has additional build targets that are not supported by TI. To find these read the ‘boards.cfg’ file and look for the build target listed above. And please note that the main config file will leverage other files under include/configs, as seen by #include statements.

Note

BINMAN_INDIRS is used to fetch the DM binary from board-support/prebuilt-images/ti-dm/ and SYSFW binaries from board-support/prebuilt-images/ti-sysfw/. If not using the SDK, BINMAN_INDIRS can point to either ti-linux-firmware or any folder where DM is located in <path to folder>/ti-dm/ and SYSFW binaries are present in <path to folder>/ti-sysfw/. Please make sure to use the absolute path.

3.1.1.1.3. Image Formats

  • tiboot3.bin

+-----------------------+
|        X.509          |
|      Certificate      |
| +-------------------+ |
| |                   | |
| |        R5         | |
| |   u-boot-spl.bin  | |
| |                   | |
| +-------------------+ |
| |                   | |
| |     FIT header    | |
| | +---------------+ | |
| | |               | | |
| | |   DTB 1...N   | | |
| | +---------------+ | |
| +-------------------+ |
+-----------------------+
  • tispl.bin

+-----------------------+
|                       |
|       FIT HEADER      |
| +-------------------+ |
| |                   | |
| |      ARM64 ATF    | |
| +-------------------+ |
| |                   | |
| |     ARM64 OPTEE   | |
| +-------------------+ |
| |                   | |
| |      ARM64 SPL    | |
| +-------------------+ |
| |                   | |
| |   SPL DTB 1...N   | |
| +-------------------+ |
+-----------------------+
  • sysfw.itb

+-----------------------+
|                       |
|       FIT HEADER      |
| +-------------------+ |
| |                   | |
| |     sysfw.bin     | |
| +-------------------+ |
| |                   | |
| |    board config   | |
| +-------------------+ |
| |                   | |
| |     PM config     | |
| +-------------------+ |
| |                   | |
| |     RM config     | |
| +-------------------+ |
| |                   | |
| |    Secure config  | |
| +-------------------+ |
+-----------------------+

3.1.1.1.4. Boot Flow

Booting the Linux kernel on an embedded platform is not as simple as simply pointing a program counter to the kernel location and letting the processor run. This section will review the four bootloader software stages that must be run before the kernel can be booted and run on the device.

Application processors such as the the AM335x are complex pieces of hardware, but have limited internal RAM (e.g., 128KB). Because of this limited amount of RAM, multiple bootloader stages are needed. These bootloader stages systematically unlock the full functionality of the device so that all complexities of the device are available to the kernel.

There are four distinct bootloader stages:

../../../_images/U-Boot_Boot_Order_32bit.png
  1. ROM Code

The first stage bootloader is housed in ROM on the device. The ROM code is the first block of code that is automatically run on device start-up or after power-on reset (POR). The ROM bootloader code is hardcoded into the device and cannot be changed by the user. Because of this, it is important to get an understanding of what exactly the ROM code is doing.

The ROM code has two main functions:

  • Configuration of the device and initialization of primary peripherals such as stack setup, configuring the Watchdog Timer (see TRM for details) as well as the PLL and system clocks configuration

  • Readies the device for next bootloader by checking boot sources for next stage of bootloader (SPL) as well as loading the actual next stage bootloader code into memory and starting it

The list of booting devices that the ROM code will search through for the second stage bootloader is configured by the voltage levels set on the devices SYSBOOT pins on startup. These pins also set other boot parameters (i.e. expected crystal frequency, bus width of external memory). For more information on the SYSBOOT pins and associated boot parameters see the device TRM.

  1. SPL or MLO

The second stage bootloader is known as the SPL (Secondary Program Loader), but is sometimes referred to as the MLO (MMC Card Loader). The SPL is the first stage of U-Boot, and must be loaded from one of the boot sources into internal RAM. The SPL has very limited configuration or user interaction, and mainly serves to initialize the external DDR memory and set-up the boot process for the next bootloader stage: U-Boot.

  1. U-Boot

U-Boot allows for powerful command-based control over the kernel boot environment via a serial terminal. The user has control over a number of parameters such as boot arguments and the kernel boot command. In addition, U-Boot environment variables can be configured. These environment variables are stored in the uEnv.txt file on your storage medium or directly in a Flash-based memory if configured such. These environment variables can be viewed, modified, and saved using the env print, env set, and env save commands, respectively. U-Boot is also a very useful tool to program and manipulate a wide range of external memory devices as well as a helpful aid during custom board bringup.

  1. Linux Kernel

zImage is the compressed kernel image wrapped with header info that describes the kernel. This header includes the target architecture, the operating system, kernel size, entry points, etc. The loading of the kernel image is typically performed through the use of scripts stored in the U-Boot environment (all starting with the bootcmd ENV variable that gets executed after the autoboot countdown expires or manually by entering the boot command at the U-Boot prompt). This also involves passing a board- specific device tree blob (DTB) as an argument to U-Boot’s bootz command that will extract and start the actual kernel.

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 R5 SPL bootloader stage

The SRAM memory layout explains the memory used for Bootloader’s operation.