[Tutorial] Build, customize and use MediaTek open-source U-Boot and ATF

This tutorial will help you to build, use and customize the official u-boot and atf (TF-A) from MediaTek SDK.

1. Source code

U-Boot: https://github.com/mtk-openwrt/u-boot
ATF: https://github.com/mtk-openwrt/arm-trusted-firmware

2. Toolchain

This tutorial talks only about the ARM 64-bit platforms. So you need only the aarch64 toolchain.
You can use the openwrt toolchain which can be found in staging_dir/toolchain-aarch64_XXXXX

3. Configure u-boot

Here is a list for all defconfigs supports MediaTek-specific features (Bootmenu with upgrading/booting support)

Name Boot device Description
mt7622_emmc_rfb_defconfig eMMC (dev 0)****
mt7622_nmbm_rfb_defconfig SPI-NAND (SNFI)* NMBM enabled. Uses squashfs + jffs2
mt7622_nmbm_ubi_rfb_defconfig SPI-NAND (SNFI) NMBM enabled. Uses UBI
mt7622_nor_rfb_defconfig SPI-NOR***
mt7622_sd_rfb_defconfig SD (dev 1)****
mt7622_snand_ubi_rfb_defconfig SPI-NAND (SNFI) Uses UBI
mt7981_emmc_rfb_defconfig eMMC
mt7981_sd_rfb_defconfig SD
mt7981_snfi_nand_rfb_defconfig SPI-NAND (SNFI) NMBM enabled. Uses UBI
mt7981_spim_nand_rfb_defconfig SPI-NAND** NMBM enabled. Uses UBI
mt7981_spim_nor_rfb_defconfig SPI-NOR
mt7986_snfi_nand_rfb_defconfig SPI-NAND (SNFI) NMBM enabled. Uses UBI
mt7986_spim_nand_rfb_defconfig SPI-NAND NMBM enabled. Uses UBI
mt7986_spim_nor_rfb_defconfig SPI-NOR
mt7986a_bpir3_emmc_defconfig eMMC
mt7986a_bpir3_sd_defconfig SD

* SPI-NAND (SNFI) means the SPI-NAND is connected to the MediaTek SPI-NAND Flash Interface (SNFI), a dedicated controller for SPI-NAND flashes using MTK's HW ECC engine instead of the On-die ECC engine from SPI-NAND chip.
** SPI-NAND without SNFI means the SPI-NAND is connected to the standard spi-mem controller.
*** MT7622 uses a dedicated SPI-NOR controller while MT7981/MT7986 use standard spi-mem controller.
**** MT7622 has two SD/eMMC controllers (called MSDC), the first one always connects to the eMMC and the second one always connects to SD.

To configure the u-boot, please run the following command in u-boot source directory:

make XXXXX_defconfig

4. Compile u-boot

Run the following command in u-boot source directory:

make CROSS_COMPILE=<toolchain-prefix>

Assume you have a toolchain located at ~/openwrt/staging_dir/toolchain-aarch64_cortex-a53_gcc-8.4.0-musl, and a directory named aarch64-openwrt-linux is inside the toolchain base directory, the toolchain-prefix will be:

~/openwrt/staging_dir/toolchain-aarch64_cortex-a53_gcc-8.4.0-musl/bin/aarch64-openwrt-linux-

If no error occurs, the target file is u-boot.bin.

5. Compile ATF

To compile ATF, we have to pass several configuration parameters to the make command line.

The overall command line is:

make -f Makefile PLAT=<plat> BOOT_DEVICE=<bootdevice> BL33=<path-to-u-boot.bin> <optional-options> all fip

If no error occurs, the target file are bl2.img and fip.bin located in

<atf-src-dir>/build/<plat>/release

a) Essential parameters:

PLAT=

Possible values: mt7622/mt7981/mt7986

BOOT_DEVICE=

Value Boot device Description
nor SPI-NOR
snand SPI-NAND (SNFI) optional NAND_TYPE= may be needed
spim-nand SPI-NAND optional NAND_TYPE= may be needed
emmc eMMC
sdmmc SD optional DEVICE_HEADER_OFFSET= may be need by mt7622
ram - For debugging purpose only

b) Optional parameters:

NAND_TYPE=

This option is valid only when BOOT_DEVICE= is set to snand or spim-nand.

By default NAND_TYPE= will be set to default value if not specified.

Important notice: NAND_TYPE must match the memory organization of the SPI-NAND chip otherwise the device will not boot.

Value Boot device Platform Description
2k+64 snand mt7622 Page size: 2K, Spare size: 64 (default)
2k+128 snand mt7622 Page size: 2K, Spare size: 128
4k+256 snand mt7622 Page size: 4K, Spare size: 256
hsm:2k+64 snand mt7981/mt7986 Page size: 2K, Spare size: 64 (default)
hsm:2k+128 snand mt7981/mt7986 Page size: 2K, Spare size: 128
hsm:4k+256 snand mt7981/mt7986 Page size: 4K, Spare size: 256
spim:2k+64 spim-nand mt7981/mt7986 Page size: 2K, Spare size: 64 (default)
spim:2k+128 spim-nand mt7981/mt7986 Page size: 2K, Spare size: 128
spim:4k+256 spim-nand mt7981/mt7986 Page size: 4K, Spare size: 256

NMBM=

This option is valid only when BOOT_DEVICE= is set to snand or spim-nand.

Value Description
0 Disable NMBM (default)
1 Enable NMBM

DRAM_USE_DDR4=

This option is valid only for mt7981/mt7986.

Value Description
0 The DRAM chip is DDR3 (default)
1 The DRAM chip is DDR4

DDR3_FLYBY=

This option is valid only for mt7622.

Value Description
0 The board uses only one DRAM chip (default)
1 The board uses two dram chips (For BPI-R64)

BOARD_BGA=

This option is valid only for mt7981.

Value Description
0 The chip package is QFN (MT7981C) (default)
1 The chip package is BGA (MT7981A/MT7981B)

RAM_BOOT_DEBUGGER_HOOK=

This option is valid only when BOOT_DEVICE= is set to ram.
By using this option, the bl2.bin can be load by OpenOCD for debricking.
Please refer to: https://github.com/mtk-openwrt/openocd-scripts/tree/main/mt7622

Value Description
0 Disable debugger hook (default)
1 Enable debugger hook

DEVICE_HEADER_OFFSET=

This option is valid only when PLAT is mt7622 and BOOT_DEVICE= is set to sdmmc.
This option specify the absolute address of the BL2 in the SD card.
This value must match the real address of the BL2 in the SD card otherwise the device will not boot.
The default value is 0x80000.

ENABLE_JTAG=

This option is valid only when PLAT is mt7981/mt7988.
By default JTAG will be disabled in BL2.

Value Description
0 Disable JTAG (default)
1 Enable JTAG

USE_MKIMAGE= and MKIMAGE=

If you don't want to use the closed-source program bromimage to generate bl2.img, you can use the open-source replacement —— The mkimage from u-boot. We already add support for mt7622 to upstream. To support mt7981/mt7986, you must use the mkimage from the u-boot linked in section 1.

To enable using mkimage, these two parameters must be used together:

USE_MKIMAGE=1 MKIMAGE=<path-to-mkimage>

c) Examples

Build for BPI-R64 booting from SPI-NAND:

make -f Makefile PLAT=mt7622 BOOT_DEVICE=snand DDR3_FLYBY=1 all fip

Build for MT7986 booting from SD using DDR4:

make -f Makefile PLAT=mt7986 BOOT_DEVICE=sdmmc DRAM_USE_DDR4=1 all fip

6. Upgrade the new U-Boot and ATF

The final files are bl2.img and fip.bin. You can upgrade them from anywhere, e.g. from u-boot bootmenu or from linux shell of OpenWrt.

7. Breif introduction of MediaTek-specific u-boot features

Four commands are added:

Command Description
mtkautoboot Display MediaTek-specific bootmenu
mtkupgrade Start interactive prompt for firmware/bootlaoder upgrading
mtkload Start interactive prompt for loading data to ram
mtkboardboot Automatically boot the firmware

mtkautoboot

This command is also the autoboot command for u-boot.
A menu will be displayed like this:

  *** U-Boot Boot Menu ***

      1. Startup system (Default)
      2. Upgrade firmware
      3. Upgrade ATF BL2
      4. Upgrade ATF FIP
      5. Upgrade single image
      6. Load image
      0. U-Boot console

You can choose whatever you want.

mtkupgrade

This command has one optional parameter:
mtkupgrade [part]

Part Description
bl2 Upgrade BL2
fip Upgrade FIP
gpt Upgrade GPT for SD/eMMC
simg Upgrade single image (ROM dump), not recommended for use

If mtkupgrade is called without parameter, it will first ask you to choose a part:

Available parts to be upgraded:
    0 - ATF BL2
    1 - ATF FIP
    2 - Firmware
    3 - Single image

Select a part:

Just press a number to select a part.

After you slect the part, or you just called this command with the part parameter, it will ask you to choose a transmission method:

*** Upgrading ATF BL2 ***

Available load methods:
    0 - TFTP client (Default)
    1 - Xmodem
    2 - Ymodem
    3 - Kermit
    4 - S-Record

Select (enter for default):

Again, press a number to select a method. You can also press enter directly to select TFTP client.

If you selected TFTP client, it will then ask you for some network configurations:

Input U-Boot's IP address: 192.168.1.1
Input TFTP server's IP address: 192.168.1.2
Input IP netmask: 255.255.255.0
Input file name: bl2.img

After all prompts above, this command will start to receive file data and then write it to the flash device:

Using ethernet@15100000 device
TFTP from server 192.168.1.2; our IP address is 192.168.1.1
Filename 'bl2.img'.
Load address: 0x46000000
Loading: ##############
         94.7 KiB/s
done
Bytes transferred = 200888 (310b8 hex)
Saving Environment to MTD... Erasing on MTD device 'u-boot-env'... OK
Writing to MTD device 'u-boot-env'... OK
OK

*** Loaded 200888 (0x310b8) bytes at 0x46000000 ***

Erasing 'bl2' from 0x0, size 0x32000 ... OK
Writing 'bl2' from 0x46000000 to 0x0, size 0x310b8 ... OK

*** ATF BL2 upgrade completed! ***

mtkload

This command is similar to mtkupgrade, but only load data into memory.

mtkboardboot

This command will boot firmware according to configuration:

a) Bootmenu type is set to SD/eMMC:

  • Try to boot kernel from the partition named kernel defined in GPT.

b) Bootmenu type is set to MTD:

  • If both kernel and ubi partition exist, it will boot kernel from mtd partition kernel.
  • If only ubi partition exists, it will try to load and boot kernel from ubi volume named kernel.
  • If only firmware partition exists, it will boot kernel from mtd partition firmware.

8. Customization of U-Boot

After running defconfig command for u-boot, you can use menuconfig to modify the MediaTek-specific features:

Bootmenu

ARM architecture > MediaTek specific configurations > Enable bootmenu framework

Use default bootmenu: You can deselect this to use a customized bootmenu implementation (entries, command actions, ...).
Default bootmenu implementation file is:
board/mediatek/common/bootmenu_mmc.c
board/mediatek/common/bootmenu_mtd.c
An customized example is the mt7629 legacy bootmenu:
board/mediatek/mt7629/bootmenu_mtd_legacy.c

Device type for bootmenu:
a) MTD (NOR/NAND/UBI): Based on mtdparts:

  • If both kernel and ubi partition exist -> Upgrade kernel to kernel partition, upgrade rootfs to rootfs vaolume in ubi partition.
  • If only ubi partition exists -> Upgrade both kernel and rootfs to volumes in ubi partition.
  • If only firmware partition exists -> Upgrade firmware image to firmware partition

b) SD/eMMC

  • If mmc device is eMMC -> Upgrade BL2 to boot0 hw partition.
  • If mmc device is SD -> Upgrade BL2 to bl2 partition defined in GPT.
  • Upgrade both kernel and rootfs to partitions defined in GPT.

Enable bootmenu countdown: You can deselect this to make u-boot stop booting on this menu. This is mainly used for debugging (Load by OpenOCD)
MediaTek bootmenu delay time: This is an idependent to standard bootmenu and autoboot. Specify the delay time for bootmenu displayed by mtkautoboot command.

Enable support for loading from SD card: When both mmc support, partition support and FS support are enabled, enabling this option will add a new file loading method for mtkupgrade command to support load file from SD partition.
MMC device index for SD card: The mmc device index of the SD card. 1 for mt7622, 0 for other chips.

Enable support for UBI-based images: Enable this option to allow mtkupgrade and mtkautoboot commands to deal with ubi volume and tarball sysupgrade image.

NMBM

ARM architecture > MediaTek specific configurations > Enable NAND bad block mapping management

Lower MTD device name: The raw nand mtd device. Currently spi-nand0 for all chips.

You should also define proper mtdparts described in next section.

MTD partition table

The bootmenu type MTD requires mtd partition table be defined properly.

Command line interface > Filesystem commands

Default MTD IDs:

  • nor0=nor0 for SPI-NOR
  • spi-nand0=spi-nand0 for SPI-NAND without NMBM
  • nmbm0=nmbm0 for SPI-NAND with NMBM

Default MTD partition:

  • For SPI-NOR, firmware partition must be defined
  • For SPI-NAND + UBI: define only ubi partition if both kernel and rootfs are stored as ubi volumes; define both kernel and ubi partition if only rootfs is stored as ubi volume.

9. Customization of ATF

Actually these is only one thing can be customized —— The offse and size of FIP partition for SPI-NOR and SPI-NAND.

Open files named bl2_boot_nor.c, bl2_boot_snand.c, bl2_boot_spim_nand.c or bl2_boot_spim_nor.c located in plat/mediatek/<plat>/

Find and modify the following lines:

#define FIP_BASE			0x380000
#define FIP_SIZE			0x200000

or

#define FIP_BASE_NOR	0x100000
#define FIP_SIZE_NOR	0x80000

10. Generating GPT data

A tool is provided in the ATF repo: tools/dev/gpt_editor
mtk_gpt.py requires python 2.7

A quick start command line:

python mtk_gpt.py --i <gpt-json> --o <output-gpt>

<gpt-json> defines each partition. Examples can be found in example folder.
<output-gpt> is the actual GPT raw data that can be written to the start of SD/eMMC data region, or be upgraded by mtkupgrade command.

Notes:

  • The only difference for SD and eMMC partitions is that bl2 partition does not exist for eMMC.
  • There is no limit for bl2 partition for SD cards of MT7981/mt7986. You can modify its start offset and size at will.

GPT for MT7622 SD

The GPT for MT7622 booting from SD is special:
Although we uses GPT, the bootrom of MT7622 actually uses MBR. And an additional limit is that the device header offset in BL2 header must match the real offset of BL2 in SD card.

One can generate valid GPT data for MT7622 SD, with the following steps:

  1. Use the example file mt7986-sd.json to generate the initial GPT data
python mtk_gpt.py --i example/mt7986-sd.json --o GPT_SD
  1. Use the start block num of BL2 to calculate device header offset:
	"bl2" : {
		"start": 1024,
		"end" : 8191,
		"attributes": 4,
		"uuid" : "{19a4763a-6b19-4a4b-a0c4-8cc34f4c2b8a}"
	},

So the start block of BL2 is 1024, device header offset is 1024 * 512 = 0x80000.
When compiling the ATF, pass DEVICE_HEADER_OFFSET=0x80000 to the make command line.
You can actually omit this if the offset id the default value 0x80000.

  1. Use WinHex or other editor to add the second partition to MBR partition table:

    * 7168 = 8191 -1024 + 1
5 Likes