[TOC]
Basic Introduction
Feature
v2017(next-dev) is a version branched from the official U-Boot v2017.09 release for development by RK. It currently supports all mainstream RK chips currently on sale. The main supported features include:
- Support for RK Android firmware boot;
- Support for Android AOSP firmware boot;
- Support for Linux Distro firmware boot;
- Support for both Rockchip miniloader and SPL/TPL Pre-loader boot;
- Support for LVDS, EDP, MIPI, HDMI, CVBS, RGB and other display devices;
- Support for eMMC, Nand Flash, SPI Nand flash, SPI NOR flash, SD card, USB drive and other storage device boot;
- Support for FAT, EXT2, EXT4 file systems;
- Support for GPT, RK parameter partition tables;
- Support for boot LOGO, charging animation, low battery management, power management;
- Support for I2C, PMIC, CHARGE, FUEL GUAGE, USB, GPIO, PWM, GMAC, eMMC, NAND, Interrupt, etc.;
- Support for Vendor storage to save user data and configuration;
- Support for RockUSB and Google Fastboot USB gadget flashing of eMMC;
- Support for Mass storage, ethernet, HID and other USB devices;
- Support for dynamically selecting kernel DTB based on hardware status;
Version
RK has two versions of U-Boot: the old v2014 version and the new v2017 version, internally named rkdevelop and next-dev respectively. Users can confirm whether the current U-Boot is the v2017 version in two ways.
Method 1: Check if the version number in the root Makefile is 2017.
#
# SPDX-License-Identifier: GPL-2.0+
#
VERSION = 2017
PATCHLEVEL = 09
SUBLEVEL =
EXTRAVERSION =
NAME =
......
Method 2: Check if the first formal print line at boot is U-Boot 2017.09.
U-Boot 2017.09-01818-g11818ff-dirty (Nov 14 2019 - 11:11:47 +0800)
......
Open Source: v2017 is open source and regularly updated on Github: https://github.com/rockchip-linux/u-boot
Kernel Version: v2017 requires RK kernel version >= 4.4
DM
DM (Driver Model) is the standard device-driver development model in U-Boot, very similar to the kernel's device-driver model. The v2017 version also follows the DM framework for developing various functional modules. It is recommended that readers first read the DM documentation to understand the DM architecture principles and implementation.
README:
./doc/driver-model/README.txt
Terminology
-----------
Uclass - a group of devices which operate in the same way. A uclass provides
a way of accessing individual devices within the group, but always
using the same interface. For example a GPIO uclass provides
operations for get/set value. An I2C uclass may have 10 I2C ports,
4 with one driver, and 6 with another.
Driver - some code which talks to a peripheral and presents a higher-level
interface to it.
Device - an instance of a driver, tied to a particular port or peripheral.
Brief summary:
- uclass: Device driver model
- driver: Driver
- device: Device
Core code:
./drivers/core/
Security
U-Boot belongs to the Non-Secure World in the ARM TrustZone security system and cannot directly access any secure resources (such as secure memory, secure otp, efuse...). It needs to access them indirectly through trust. CPU operation modes of U-Boot on the RK platform:
32-bit platform: Non-Secure PL1
64-bit platform: EL2(Always be Non-Secure)
Boot-order
Depending on whether the previous stage loader code is open source, the RK platform currently has two boot methods:
// Previous stage loader closed source
BOOTROM => ddr bin => Miniloader => TRUST => U-BOOT => KERNEL
// Previous stage loader open source
BOOTROM => TPL => SPL => TRUST => U-BOOT => KERNEL
TPL is equivalent to ddr bin, and SPL is equivalent to miniloader. The TPL+SPL combination achieves the same functionality as the RK closed-source ddr.bin+miniloader, and they can be interchanged.
Driver-probe
Although U-Boot has introduced the device-driver development model, it does not automatically initiate probe of registered device-drivers like the kernel during the initialization phase. The driver probe must be actively called by the user. The interfaces are as follows:
int uclass_get_device(enum uclass_id id, int index, struct udevice **devp);
int uclass_get_device_by_name(enum uclass_id id, const char *name,
struct udevice **devp);
int uclass_get_device_by_seq(enum uclass_id id, int seq, struct udevice **devp);
int uclass_get_device_by_of_offset(enum uclass_id id, int node, struct udevice **devp);
int uclass_get_device_by_ofnode(enum uclass_id id, ofnode node, struct udevice **devp);
int uclass_get_device_by_phandle_id(enum uclass_id id,
int phandle_id, struct udevice **devp);
int uclass_get_device_by_phandle(enum uclass_id id,
struct udevice *parent, struct udevice **devp);
int uclass_get_device_by_driver(enum uclass_id id,
const struct driver *drv, struct udevice **devp);
int uclass_get_device_tail(struct udevice *dev, int ret, struct udevice **devp);
......
Core call within the above interfaces:
int device_probe(struct udevice *dev); // It is recommended that users understand the internal implementation!
Shell
U-Boot's Shell is called CLI (command line interface), i.e., command line mode. Users can customize CMD according to their needs. CMD can be called not only through Shell but also programmatically via run_command() and run_command_list().
int run_command(const char *cmd, int flag)
int run_command_list(const char *cmd, int len, int flag)
Boot-Command
U-Boot ultimately boots the kernel through the boot command defined by CONFIG_BOOTCOMMAND. Before executing CONFIG_BOOTCOMMAND, the CONFIG_PREBOOT pre-boot command is also executed. This command is usually defined as empty.
TPL/SPL/U-Boot-proper
U-Boot can obtain three different functional Loaders (TPL/SPL/U-Boot-proper) from the same codebase by using different compilation conditions.
TPL (Tiny Program Loader) and SPL (Secondary Program Loader) are Loaders that run in earlier stages than U-Boot:
-
TPL: Runs in SRAM, responsible for DDR initialization;
-
SPL: Runs in DDR, responsible for system low-level initialization and loading of subsequent stage firmware (trust.img and uboot.img);
-
U-Boot proper: Runs in DDR, commonly referred to as "U-Boot", responsible for booting the kernel;
Note: The term "U-Boot proper" is mainly used to distinguish it from SPL. By convention, U-Boot proper will be simply referred to as U-Boot in subsequent chapters.
Boot flow:
BOOTROM => TPL(ddr bin) => SPL(miniloader) => TRUST => U-BOOT => KERNEL
More references: doc/README.TPL and doc/README.SPL
Build-Output
After U-Boot compilation succeeds, some important files are generated in the root directory (TPL/SPL output files only exist when TPL/SPL compilation is enabled):
// U-Boot stage
./u-boot.map // MAP table file
./u-boot.sym // SYMBOL table file
./u-boot // ELF file, similar to kernel vmlinux (important!)
./u-boot.dtb // U-Boot's own dtb file
./u-boot.bin // Executable binary file, will be packaged into uboot.img for flashing
// SPL stage
./spl/u-boot-spl.map // MAP table file
./spl/u-boot-spl.sym // SYMBOL table file
./spl/u-boot-spl // ELF file, similar to kernel vmlinux (important!)
./spl/u-boot-spl.dtb // SPL's own dtb file
./spl/u-boot-spl.bin // Executable binary file, will be packaged into loader for flashing
// TPL stage
./tpl/u-boot-tpl.map // MAP table file
./tpl/u-boot-tpl.sym // SYMBOL table file
./tpl/u-boot-tpl // ELF file, similar to kernel vmlinux (important!)
./tpl/u-boot-tpl.dtb // TPL's own dtb file
./tpl/u-boot-tpl.bin // Executable binary file, will be packaged into loader for flashing
Environment-Variables
ENV (Environment-Variables) is a global data management and transfer method supported by U-Boot. The principle is to build a HASH mapping table that manages user data as table entries in the format of "key-value data".
ENV is typically used to define platform configuration parameters: firmware load addresses, network configuration (ipaddr, serverip), bootcmd, bootargs, etc. Users can print them using the printenv command on the command line.
- Users can choose whether to save ENV data to local storage
- ENV data is limited to use within U-Boot and cannot be directly passed to the kernel; the kernel cannot directly parse it either
- User space can access ENV data through the fw_printenv tool provided by U-Boot
The storage address and size of ENV data on the RK platform are defined as follows (unit: bytes):
if ARCH_ROCKCHIP
config ENV_OFFSET
hex
depends on !ENV_IS_IN_UBI
depends on !ENV_IS_NOWHERE
default 0x3f8000
help
Offset from the start of the device (or partition)
config ENV_SIZE
hex
default 0x8000
help
Size of the environment storage area
endif
U-Boot DTS
U-Boot has its own DTS file, which is automatically generated during compilation into the corresponding DTB file, appended to the end of u-boot.bin. File directory:
arch/arm/dts/
Which DTS file each platform uses is specified by CONFIG_DEFAULT_DEVICE_TREE in the defconfig.
Relocation
Typically during the boot phase, U-Boot is loaded into low DRAM addresses by the previous stage bootloader. After completing the board_f.c flow, U-Boot relocates itself to a reserved address at the end of memory (this process is called relocation. The address depends on U-Boot's memory layout). After relocation is complete, it continues with the board_r.c flow. This can be identified from the boot log:
U-Boot 2017.09-gabfd1c5e3d-210202-dirty #cjh (Mar 08 2021 - 16:57:31 +0800)
Model: Rockchip RK3568 Evaluation Board
PreSerial: 2, raw, 0xfe660000
DRAM: 2 GiB
Sysmem: init
// Relocated to ddr base address offset 0x7d304000. If 0, no relocation was performed.
Relocation Offset: 7d304000, fdt: 7b9f8ed8
Using default environment
......