NEXEMBED

Key takeaway: Das U-Boot is a modular, two-stage (sometimes three-stage) bootloader that starts where the SoC’s on-chip ROM ends and hands off to an operating system. Because every board differs, real-world projects almost always rebuild, prune or extend U-Boot. Mastering its SPL/TPL architecture, driver model, devicetree, environment system and build flow lets you shrink boot time, add new peripherals, secure the chain of trust and create production-ready update mechanisms.

1 Boot Flow and Internal Architecture

StageWho loads itRuns fromPrincipal duties
SoC Boot ROMFixed in siliconInternal SRAMLocate first image, set up tiny stack
TPL (optional)ROML1/L2 cache as SRAMLoad SPL when even 32-64 kB SRAM is tight1
SPLROM / TPLOn-chip SRAMInit DDR, clocks, PMIC; load U-Boot proper or directly Linux (Falcon mode)123
VPL (optional)SPLDDRAuthenticates/chooses signed SPLs for A/B or verified boot1
U-Boot properSPLDDRExposes CLI, driver model, network & filesystem stacks, loads OS kernel4

SPL is intentionally minimal: it drops shell commands, networking and most drivers to fit tens of kilobytes. U-Boot proper contains the full command set and the driver model that probes hardware before booting the OS.

2 Core Subsystems

2.1 Driver Model (DM)

U-Boot switched from ad-hoc, #ifdef-heavy drivers to a uclass / driver / device hierarchy.

  • Each uclass (GPIO, SPI, USB, …) defines a common API.
  • A driver implements that API for a given IP block.
  • A device is an instantiation described by devicetree or static data.

Benefits include automatic probing, power-domain ordering and near-zero code duplication. New peripherals are added by declaring:

cstatic const struct spi_ops my_spi_ops = { … };

U_BOOT_DRIVER(my_spi_drv) = {
    .name  = "my_spi",
    .id    = UCLASS_SPI,
    .ops   = &my_spi_ops,
    .of_match = my_spi_ids,
    .priv_auto_alloc_size = sizeof(struct my_spi_priv),
};

2.2 Devicetree in U-Boot

When CONFIG_OF_CONTROL=y, a flattened devicetree (FDT) is embedded or loaded at runtime to describe clocks, GPIOs or even which drivers DM should bind. One binary can therefore support several boards by appending the correct DTB at boot.
U-Boot keeps a second, leaner DTB for SPL so that DRAM init can still use libfdt even before full driver model is available.

2.3 Environment Variables

A CRC-protected key–value store holds bootcmd, bootargs, Ethernet MACs, update scripts, etc. The store lives in NOR/NAND, eMMC, SPI-flash or UBI and is copied to RAM on power-up.
env set, env save and env print manipulate it from the shell; fw_printenv/fw_setenv offer the same service from Linux user space.

VariablePurpose
bootcmdScript executed after bootdelay expires
bootargsKernel command line
bootdelaySeconds before auto-boot
ethaddr / ipaddrNetwork identity
dfu_alt_infoDFU update descriptors

3 Building and Porting U-Boot

3.1 Typical Workflow

  1. Clone & configure bashgit clone https://source.denx.de/u-boot/u-boot.git export CROSS_COMPILE=arm-linux-gnueabi- make myboard_defconfig
  2. Patch board files
    • include/configs/<board>.h – high-level Kconfig overrides.
    • board/<vendor>/<board>/ – DDR init, pinmux, power.
  3. Add/modify DTs
    arch/arm/dts/<soc>-<board>.dts plus an optional <soc>-u-boot.dtsi with u-boot,dm-spl; tags to keep SPL lean.
  4. Iterate with serial debug
    Enable CONFIG_DEBUG_UART=y and CONFIG_DEBUG_UART_SKIP_INIT=y to print from the very first instruction in SPL.

Free-Electrons (Bootlin) and Chromium guides walk step-by-step through SoC bring-up and driver reuse.

3.2 Customizing for Production

  • Boot-time reduction:
    • Skip U-Boot proper by letting SPL load a FIT that contains kernel+DT (Falcon mode).
    • Strip features with CONFIG_DISTRO_DEFAULTS off and CONFIG_AUTOBOOT_KEYED on.
  • Secure/verified boot:
    Build FIT images signed with RSA; VPL or U-Boot proper checks signatures before executing.
  • Field updates:
    Add dfu 0 mmc 0 to environment or compile the EFI capsule command set for UEFI-based updates.

4 Advanced Customization Scenarios

4.1 Adding a New Peripheral Driver

  1. Create a driver under drivers/<subsys>/.
  2. Register it with U_BOOT_DRIVER.
  3. Describe the hardware in DT (compatible = "vendor,my-ip").
  4. Add a Kconfig option so make menuconfig can enable it.

Because DM uses the same call patterns as Linux, many drivers are ported with minimal changes—polling replaces IRQs and dynamic memory use is reduced.

4.2 Board-Specific Start-Up Script

Embed manufacturing or recovery logic:

text# boot.scr (Hush)
if test "${upgrade_available}" = "1"; then
    echo "Applying update...";
    run do_upgrade; setenv upgrade_available 0; env save;
fi
run distro_bootcmd

Compile with:

bashmkimage -T script -C none -n "Boot Script" -d boot.scr boot.scr.uimg

and point bootcmd=source ${scriptaddr}.

4.3 Dual-Slot A/B Scheme

Store two FIT images plus two U-Boot SPLs. A small VPL evaluates rollback indices and chooses the newest valid pair. Environment variables track slot status (boot_a_ok, upgrade_available).

5 Debugging and Maintenance

  • bdinfo, fdt addr, fdt print—inspect memory map and live devicetree.
  • dm tree—list probed devices and uclasses.
  • crc32 ${loadaddr} ${filesize}—verify payload integrity.
  • env default -a—recover from a corrupted environment.

When hardware is silent, JTAG or SoC ROM traces help verify that SPL is actually running before DDR training.

6 Best-Practice Checklist

  1. Keep SPL tiny: only one console, one storage and DRAM init code.
  2. Let devicetree drive configuration: hard-coding GPIO numbers in C prevents board reuse.
  3. Version-control the environment: store a .env text file in the U-Boot tree and set CONFIG_ENV_SOURCE_FILE for reproducible builds.
  4. Upstream early: the mainline tree already supports hundreds of boards; merging avoids re-base pain and shares the maintenance load.
  5. Automate boot tests: run KernelCI-style jobs that power-cycle hardware and check that SPL/U-Boot banners and kernel login appear.

Conclusion

Understanding where U-Boot splits (ROM → TPL → SPL → U-Boot), how its driver model binds devices, and why environment and devicetree exist twice is the foundation for fast boot times, reliable updates and secure products. Whether you merely tweak bootcmd or create a fully signed, A/B-capable loader, the same internals apply—and with its upstream community and Linux-like APIs, U-Boot rewards engineers who embrace its architecture.

error: Content is protected !!