[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

You also need dtc tool to compile .dts files for ATF. It can be found in:

  1. device-tree-compiler package in Ubuntu for example
  2. scripts/dtc from a compiled u-boot/kernel source tree

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
mt7988_snfi_nand_rfb_defconfig SPI-NAND (SNFI) NMBM enabled. Uses UBI
mt7988_spim_nand_rfb_defconfig SPI-NAND** NMBM enabled. Uses UBI
mt7988_spim_nor_rfb_defconfig SPI-NOR
mt7988_emmc_rfb_defconfig eMMC
mt7988_sd_rfb_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/mt7988

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
hsm20:2k+64 snand mt7988 Page size: 2K, Spare size: 64 (default)
hsm20:2k+128 snand mt7988 Page size: 2K, Spare size: 128
hsm20:4k+256 snand mt7988 Page size: 4K, Spare size: 256
spim:2k+64 spim-nand mt7981/mt7986/mt7988 Page size: 2K, Spare size: 64 (default)
spim:2k+128 spim-nand mt7981/mt7986/mt7988 Page size: 2K, Spare size: 128
spim:4k+256 spim-nand mt7981/mt7986/mt7988 Page size: 4K, Spare size: 256

NMBM=

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

Value Description
0 Disable NMBM (default)
1 Enable NMBM

UBI=

Enable this option if FIP is located in a volume of UBI.
This option is valid only when BOOT_DEVICE= is set to snand or spim-nand.
This option is incompatible with NMBM=1

Value Description
0 Disable Full-UBI layout (default)
1 Enable Full-UBI layout

DRAM_USE_DDR4=

This option is valid only for mt7981/mt7986/mt7988.
MT7988: this is used for single DDR4 chip.

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

DRAM_USE_COMB=

When this option suppresses DRAM_USE_DDR4.
This option is valid only for mt7988.

Value Description
0 No effect (default)
1 The MT7988 CPU uses KGD DDR die, or the board is using two DDR chips

DDR4_4BG_MODE=

This option must be used with DRAM_USE_COMB=1.
This option is valid only for mt7988.

Value Description
0 No effect (default)
1 Enable DDR4 32-bit 8GBytes mode

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.

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

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

OVERRIDE_FIP_BASE= and OVERRIDE_FIP_SIZE=

If both specified, they will override the default FIP base & size provided by each platform.
These options have no effect if UBI=1.

OVERRIDE_UBI_START_ADDR=

These options is only valid for UBI=1.
If specified, it will override the default UBI partition start address, which is 0x200000.

OVERRIDE_UBI_END_ADDR=

These options is only valid for UBI=1 and OVERRIDE_UBI_START_ADDR is set.
If specified, it will override the default UBI partition end address, which is 0, meaning the end of NAND.

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

Five 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
httpd Start Web-based failsafe for upgrading 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 ATF BL31 only
      6.   Upgrade bootloader only
      7. Upgrade single image
      8. Load image
      9. Start Web failsafe

You can choose whatever you want.

mtkupgrade

This command has one optional parameter:
mtkupgrade [part]

Part Description
bl2 Upgrade BL2
fip Upgrade FIP
bl31 Upgrade BL31 of ATF FIP
bl33 Upgrade BL33 (Bootloader) of ATF 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 - BL31 of ATF FIP
    3 - BL33 of ATF FIP
    4 - Firmware
    5 - Single image

Select a part:

Just press a number to select a part.

Note: FIP contains both bl31 and bl33. bl33 is normally the bootloader, i.e. u-boot.bin here.
If you choose to upgrade bl31 or bl33, mtkupgrade will read FIP into memory, replace the bl31/bl33 of the FIP, and then write FIP back to flash.

After you select 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.

httpd

This command will start a HTTP server listening on port 80. You can access to it to upgrade firmware image instead of using tftp.

8. Customization of U-Boot

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

Bootmenu

> 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
board/mediatek/common/bootmenu_mtd_legacy.c (for MT7629, which uses only one bootloader)

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 Web-based failsafe for firmware upgrading: When enabled, Web-based failsafe will start if mtkboardboot command fails. The bootmenu will also have an entry for starting Web-based failsafe.

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

> 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

There are two sets of configurations:

a) The offset and size of FIP (for nor, or snand/spim-nand with NMBM=1):
All platforms have their own default FIP offsets and sizes.
You can override them by passing the following arguments to the make command:

OVERRIDE_FIP_BASE=xxx \
OVERRIDE_FIP_SIZE=xxx

b) The start and end addresses of UBI partition (for snand/spim-nand with UBI=1)
By default the start address of UBI partition is 0x200000, and its end address is 0, which means end of flash.
You can override the start address by passing the following argument to the make command:

OVERRIDE_UBI_START_ADDR=xxx

You can also override the end address by passing the following argument to the make command if OVERRIDE_UBI_START_ADDR has been set:

OVERRIDE_UBI_END_ADDR=xxx

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

Edit history

Date Description
2023/07/05 Update for new ATF release
2023/07/20 Update for new U-Boot release
12 Likes

is it possible to enable also boot from usb?

There's no such option.
The bootrom doesn't support booting from USB.

While would be hard to have uboot supporting the xhci?

u-boot already supports that.

1 Like

I assumed it weren't. Is it enough to enable xhci support?

1 Like

Hi,

Is it possible to configure Secure Boot/program efuses on, say, a Banana Pi R3 (MT7986)?

Thanks!

What is the difference between bl2.img and bl2.bin generated by ATF?

It's possible. But we don't provide related SOP here.

1 Like

bl2.img = mtk bootrom header + bl2.bin + sha256 hash

Can the router start normally if I flash bl2.bin?
I have enabled WEB FAILSAFE during Build, but I don’t know which button on the router I need to press to enter the web page.

absolutely impossible. you've got a brick now.

Is the word "here" subjective? Is there a SOP somewhere else? Or was the original language lost in translation.

Thanks! :slight_smile:

You need to sign with MTK...

1 Like

I have flashed bl2.img and fip.bin, and configured the buttons, leds and web failsafe correctly. Which file do I need to modify to start Web failsafe by pressing the reset key?

fip.bin

more precisely it's the u-boot.bin in the fip.bin