Utilite U-Boot firmware
From Utilite Wiki
The Utilite firmware consists of two components: SPL (Secondary Program Loader), and U-Boot, both residing in a single binary cm-fx6-firmware. Both programs are compiled from the same code base; U-Boot is the fully featured bootloader, while SPL is a small subset of U-Boot, designed to run in very early stages of boot.
SPL and U-Boot play the following part in the Utilite boot sequence:
- When Utilite is powered on, the i.MX6 Internal Boot ROM runs.
- The Internal Boot ROM does some minimal hardware setup, and tries to load SPL. The Boot ROM looks for SPL image at 1KB offset, first on the MMC storage, and then (if not found) on the SPI flash.
- SPL does some additional hardware configuration, detects and configures DRAM, and then tries to load U-Boot. The SPL looks for U-Boot image at 64KB offset, first on the MMC storage, and then (if not found) on the SPI flash.
- U-Boot does the remainder of hardware configuration, relocates itself to the top of the RAM, and starts counting down to OS boot.
- If the OS boot countdown is interrupted by a user, it will be possible to interact with U-Boot via the command line. If the OS boot countdown is not interrupted, the main OS will load.
Preparing for development
Getting the tools
If developing on a non-ARM workstation, such as an x86/x64 computer, a cross compiler is required.
Cross compilers are used to generate binaries for a CPU architecture (called the "target" architecture) which is different from the CPU architecture of the workstation (called the "host" architecture). There are several options for cross-compilation toolchains that support the ARM embedded-application binary interface (EABI):
Getting U-Boot sources
- Install git version control system.
- Create and cd into a directory to where you wish to store the U-Boot source code.
- Create a clone of U-Boot tree
git clone https://github.com/utilite-computer/u-boot.git u-boot-utilite cd u-boot-utilite
- Create a branch for Utilite development.
git checkout -b my_utilite_project v2015.07-cm-fx6-3
Building the firmware images
- First, compile both SPL and U-Boot. The following commands create the spl/u-boot-spl.bin and u-boot.img binaries using the CodeSourcery toolchain:
export ARCH=arm export CROSS_COMPILE=arm-none-linux-eabi- make mrproper make cm_fx6_config && make
- Invoke mkimage on the SPL binary to attach the IVT header required by the i.MX6 boot ROM code to the SPL binary. This generates a new image file spl.img.
./tools/mkimage -n arch/arm/imx-common/spl_sd.cfg.cfgtmp -T imximage -e 0x00908000 -d spl/u-boot-spl.bin spl.img
- Create the combined image by creating a 0xFF initialized 512KB cm-fx6-firmware file, and writing the spl.img and u-boot.img data to the appropriate offsets within the cm-fx6-firmware file.
dd if=/dev/zero count=500 bs=1K | tr '\000' '\377' > cm-fx6-firmware dd if=spl.img of=cm-fx6-firmware bs=1K seek=1 conv=notrunc && dd if=u-boot.img of=cm-fx6-firmware bs=1K seek=64 conv=notrunc
- You can now install the cm-fx6-firmware file into an SD card or Utilite SPI flash.
U-Boot is configured using preprocessor macros, which are extensively documented in the README file. All the preprocessor macros for Utilite can be found in include/configs/cm_fx6.h, as well as the header files that are included into it.
Some preprocessor macros turn on features that require the implementation of board specific functions. These functions are implemented in board specific files located in the board/compulab/cm_fx6/ and board/compulab/common/ folders.
The following is a partial description of the U-Boot source code tree, focused on code that is relevant to U-Boot for Utilite.
- arch: architecture specific code
- board: U-Boot supported boards specific code.
- compulab: CompuLab boards supported by U-Boot.
- cm_fx6: Utilite specific code (SPL and U-Boot).
- common: Code common to all Compulab U-Boots.
- compulab: CompuLab boards supported by U-Boot.
- common: U-Boot commands, U-Boot environment code, SPL code, and other platform independent features.
- disk: Filesystem partitions support.
- doc: U-Boot documentaiton.
- drivers: Drivers code.
- fs: Filesystems code.
- include: Most header files are located here.
- configs: Board specific configuration files. The Utilite config file cm_fx6.h is stored here.
- lib: Compression algorithms, checksum algorithms, generic C libraries, and other hardware independent code.
- Licenses: GPL and other licenses that apply to U-Boot code.
- net: Networking code.
- scripts: Various scripts like checkpatch.pl, setlocalversion, kernel-doc, and more.
- spl: SPL images are created here.
- tools: Various tools like mkimage, buildman, patman, and more.
Working with device tree blobs
One of the responsibilities of U-Boot is to modify and pass a device tree blob to the OS. U-Boot provides a dedicated fdt command for modifying and printing device tree blobs:
CM-FX6 # help fdt fdt - flattened device tree utility commands Usage: fdt addr [-c] <addr> [<length>] - Set the [control] fdt location to <addr> fdt boardsetup - Do board-specific set up fdt move <fdt> <newaddr> <length> - Copy the fdt to <addr> and make it active fdt resize - Resize fdt to size + padding to 4k addr fdt print <path> [<prop>] - Recursive print starting at <path> fdt list <path> [<prop>] - Print one level starting at <path> fdt get value <var> <path> <prop> - Get <property> and store in <var> fdt get name <var> <path> <index> - Get name of node <index> and store in <var> fdt get addr <var> <path> <prop> - Get start address of <property> and store in <var> fdt get size <var> <path> [<prop>] - Get size of [<property>] or num nodes and store in <var> fdt set <path> <prop> [<val>] - Set <property> [to <val>] fdt mknode <path> <node> - Create a new node after <path> fdt rm <path> [<prop>] - Delete the node or <property> fdt header - Display header info fdt bootcpu <id> - Set boot cpuid fdt memory <addr> <size> - Add/Update memory node fdt rsvmem print - Show current mem reserves fdt rsvmem add <addr> <size> - Add a mem reserve fdt rsvmem delete <index> - Delete a mem reserves fdt chosen [<start> <end>] - Add/update the /chosen branch in the tree <start>/<end> - initrd start/end addr NOTE: Dereference aliases by omiting the leading '/', e.g. fdt print ethernet0.
Before fdt command can be used, a valid device tree blob should be loaded to memory, and the address of the device tree blob should be set using
fdt addr <addr>
You can now print and modify the contents of the device tree using the fdt sub commands. When you are ready to pass the device tree blob to the OS, provide its address as an argument to the boot command:
bootz <kernel addr> <initrd addr> <fdt addr>
initrd address can be omitted by passing '-' for the second argument.