wiki:venice/boot

Venice Boot Firmware

The 'Boot Firmware' for Venice is defined as the combination of the firmware stages through up to and including the bootloader. This can be broken down into the following stages:

  • Boot ROM (internal on i.MX8 SoC): fetch first level boot firmware from boot device (ie MMC or SPI FLASH) into L2 cache
  • SPL (Secondary Program Loader) - (U-Boot)
  • ATF (ARM Trusted Firmware)
  • Bootloader (U-Boot)

Gateworks provides pre-built Boot Firmware ready to flash onto boot devices as well as source for building and/or modifying the boot firmware yourself.

i.MX8 BOOT ROM

The BOOT ROM is firmware baked into the SoC and is in charge of loading code from the 'boot device' into an L2 cache scratchpad, verifying signatures (if using trusted boot) and executing it.

The BOOT ROM fetches code from an offset of 33KiB on the boot device which leaves the first 33KiB available for other firmware needs.

Boot Firmware Image

The boot firmware image contains all of the components of the 'Boot Firmware':

  • ARM Trusted Firmware (ATF)
  • SPL
  • U-Boot
  • U-Boot environment

This firmware is typically put on the eMMC boot0 hardware partition to keep it separate from the eMMC user partition used for the OS.

Venice Boot Firmware Image Map:

  • imx8mm:
start-end len item notes
0x00000000 - 0x00008400 33KiB unused
0x00008400 - 0x00060000 351KiB SPL (spl.bin) Loads and u-boot.itb and transfers control to the ATF
0x00060000 - 0x003F0000 3648KiB U-Boot (u-boot.itb) FIT image containing u-boot, ATF, and fdt
0x003F0000 - 0x00400000 64KB U-Boot env redundant 32KB env
  • imx8mn/imx8mp:
start-end len item notes
0x00000000 - 0x00058000 352KiB SPL (spl.bin) Loads and u-boot.itb and transfers control to the ATF
0x00058000 - 0x003F0000 3680KiB U-Boot(u-boot.itb) FIT image containing u-boot, ATF, and fdt
0x003F0000 - 0x00400000 64KB U-Boot env redundant 32KB env

Note that while the size of the SPL and offset/size of U-Boot can vary based on bootloader configuration the start offset of the SPL is dictated by the SOC-specific BOOTROM and varies based on the boot device and hardware partition:

  • imx8mm:
    • eMMC user partition: 33KiB
    • eMMC boot partition: 33KiB
  • imx8mn/imx8mp:
    • eMMC user partition: 32KiB
    • eMMC boot partition: 0KiB

eMMC boot partition

By default since around Jan 2024 Gateworks has been placing boot firmware on the eMMC 'boot0' hardware partition (instead of the 'user' hardware partition) which accomplishes two things:

  1. keeps your boot firmware isolated from your OS (filesystems as well as disk partition table)
  2. allows compressed disk images now representing the OS only to be shared between the various IMX8M SoC's supported by the venice family (imx8mm, imx8mn, imx8mp) which have different boot firmware images

At this same time the U-Boot environment data was moved from an offset of 0xfe0000 (16M - 128K) to an offset of 0x3e0000 (4M - 128K) so that it fit within the minimal size of the 4MB boot hardware partitions. However regardless of what hardware partition the eMMC boots from, the U-Boot environment data is always at the same offset on that hardware partition (the top of the 4MB boundary)

If you wish to move the boot firmware between user, boot0, and boot1 eMMC hardware partitions note the following:

  • the different SoC BOOT ROM's use different offsets depending on the emmc hardware partition. Specifically:
    • IMX8MM BOOT ROM will always fetch boot code at a 33KB offset for eMMC devices regardless of the hardware partition
    • IMX8MN/IMX8MP BOOT ROM will fetch boot code at a 32KB offset for eMMC devices booting from user and 0KB offset for eMMC devices booting from boot0 or boot1
  • the eMMC PARTITION_CONFIG register (EXT CSD 179) BOOT_PARTITION_ENABLE field specifies what eMMC hardware partition is active on power-up so if you move the boot firmware you must update the PARTITION_CONFIG register (via U-Boot 'mmc partconf' command, via Linux 'mmc bootpart' command (from the 'mmc-utils' package) or via JTAG by specifying the '--partconf' cmdline parameter to the mkimage_jtag script used to create a JTAG image

To determine what hardware partition is currently being used:

  • if using the latest boot firmware U-Boot SPL will announce the hardware partition such as 'Trying to boot from eMMC boot0'. If the hardware partition (boot0, boot1, user) is not shown then you are using an older boot firmware
  • use the U-Boot 'mmc partconf 2' command (2 is the eMMC device for Venice) and examine the 'BOOT_PARTITION_ENABLE' field. If using a using a newer boot firmware it will show both the numeric value as well as what that value represents, for example 'BOOT_PARTITION_ENABLE: 0x1 (boot0)' (and if just the number is shown you are using an older boot firmware). Note the possible values for BOOT_PARTITION_ENABLE are: 0x1 (boot0), 0x2 (boot1), 0x7 (user).
  • use the Linux 'mmc extcsd read' command and look at the PARTITION_CONFIG register bits[5:3]

Examples:

  • show the current eMMC boot partition:
    • from U-Boot:
      u-boot=> mmc partconf 2
      EXT_CSD[179], PARTITION_CONFIG:
      BOOT_ACK: 0x0
      BOOT_PARTITION_ENABLE: 0x1 (boot0)
      PARTITION_ACCESS: 0x0
      
      • BOOT_PARTITION_ENABLE 0x1 represents boot0 (0x1=boot0, 0x2=boot1, 0x7=user)
    • from Linux:
      root@jammy-venice:~# mmc extcsd read /dev/mmcblk2 | grep PARTITION_CONFIG
      Boot configuration bytes [PARTITION_CONFIG: 0x08]
      root@jammy-venice:~# echo $(($((0x08 >> 3)) & 0x7)) # show bits[5:3]
      1
      root@jammy-venice:~# echo $(($(( $(mmc extcsd read /dev/mmcblk2 | sed -n 's/.*PARTITION_CONFIG: \(.*\)]/\1/p') >> 3)) & 0x7)) # 1-line version
      1
      
    • BOOT_PARTITION_ENABLE is represented by bits[5:3] of PARTITION_CONFIG which can be read from the EXT CSD register 179 named 'PARTITION_CONFIG' (1=boot0, 2=boot1, 7=user)
  • IMX8MM: Program boot firmware to user:
    • from U-Boot
      # fetch flash.bin boot firmware
      tftpboot $loadaddr $dir/venice-$soc-flash.bin
      # set blkcnt to $filesize/512 (convert to 512 byte blocks)
      setexpr blkcnt $filesize + 0x1ff && setexpr blkcnt $blkcnt / 0x200
      # select the emmc (dev=2) user hardware partition (part=0)
      mmc dev 2 0
      # write to 33K (which is 0x42 hex 512 byte blocks)
      mmc write $loadaddr 0x42 $blkcnt
      # set PARTITION_CONFIG to BOOT_ACK=1 BOOT_PARTITION_ENABLE=7 to boot from user
      mmc partconf 2 1 7 0
      
    • from Linux
      # fetch flash.bin boot firmware
      wget https://dev.gateworks.com/venice/boot_firmware/venice-imx8mm-flash.bin
      # write it to mmcblk2 (user) at offset 33KB
      dd if=venice-imx8mm-flash.bin of=/dev/mmcblk2 bs=1k seek=33 conv=notrunc
      # set BOOT_PARTITION_ENABLE to 7 for mmcblk2 (eMMC)
      mmc bootpart enable 7 0 /dev/mmcblk2
      
    • via JTAG:
      # start with soc-specific position-independent boot firmware binary 
      wget https://dev.gateworks.com/venice/boot_firmware/venice-imx8mm-flash.bin
      # create a 4MB file and copy the position-independent boot firmware to where the BOOT ROM expects it (33K in this case)
      truncate -s 4M firmware.img
      dd if=venice-imx8mm-flash.bin of=firwmare.img bs=1k seek=33 conv=notrunc
      # use the mkimage_jtag script to create a JTAG binary that flashes this image and sets the PARTITION_CONFIG register
      ./mkimage_jtag --soc imx8mm --emmc -s --partconf=user \
          firmware.img@user:erase_part:0-8192 \
          > firmware-venice-imx8mm.bin
      
  • IMX8MM: Program boot firmware to boot0:
    • from U-Boot
      # fetch flash.bin boot firmware
      tftpboot $loadaddr $dir/venice-$soc-flash.bin
      # set blkcnt to $filesize/512 (convert to 512 byte blocks)
      setexpr blkcnt $filesize + 0x1ff && setexpr blkcnt $blkcnt / 0x200
      # select the emmc (dev=2) boot0 hardware partition (part=1)
      mmc dev 2 1
      # write to 33K (which is 0x42 hex 512 byte blocks)
      mmc write $loadaddr 0x42 $blkcnt
      # set PARTITION_CONFIG to BOOT_ACK=1 BOOT_PARTITION_ENABLE=1 to boot from boot0
      mmc partconf 2 1 1 0
      
    • from Linux
      # fetch flash.bin boot firmware
      wget https://dev.gateworks.com/venice/boot_firmware/venice-imx8mm-flash.bin
      # write it to mmcblk2boot0 at offset 33KB
      echo 0 > /sys/class/block/mmcblk2boot0/force_ro
      dd if=venice-imx8mm-flash.bin of=/dev/mmcblk2boot0 bs=1k seek=33 conv=notrunc
      # set BOOT_PARTITION_ENABLE to 1 for mmcblk2 (eMMC)
      mmc bootpart enable 1 0 /dev/mmcblk2
      
    • via JTAG:
      # start with soc-specific position-independent boot firmware binary 
      wget https://dev.gateworks.com/venice/boot_firmware/venice-imx8mm-flash.bin
      # create a 4MB file and copy the position-independent boot firmware to where the BOOT ROM expects it (33K in this case)
      truncate -s 4M firmware.img
      dd if=venice-imx8mm-flash.bin of=firmware.img bs=1k seek=33 conv=notrunc
      # use the mkimage_jtag script to create a JTAG binary that flashes this image and sets the PARTITION_CONFIG register
      ./mkimage_jtag --soc imx8mm --emmc -s --partconf=boot0 \
          firmware.img@boot0:erase_part:0-8192 \
          > firmware-venice-imx8mm.bin
      
  • IMX8MP: Program boot firmware to user:
    • from U-Boot
      # fetch flash.bin boot firmware
      tftpboot $loadaddr $dir/venice-$soc-flash.bin
      # set blkcnt to $filesize/512 (convert to 512 byte blocks)
      setexpr blkcnt $filesize + 0x1ff && setexpr blkcnt $blkcnt / 0x200
      # select the emmc (dev=2) user hardware partition (part=0)
      mmc dev 2 0
      # write to 32K (which is 0x40 hex 512 byte blocks)
      mmc write $loadaddr 0x40 $blkcnt
      # set PARTITION_CONFIG
      mmc partconf 2 1 user user
      
    • from Linux
      # fetch flash.bin boot firmware
      wget https://dev.gateworks.com/venice/boot_firmware/venice-imx8mp-flash.bin
      # write it to mmcblk2 (user) at offset 32KB
      dd if=venice-imx8mp-flash.bin of=/dev/mmcblk2 bs=1k seek=32 conv=notrunc
      # set BOOT_PARTITION_ENABLE to 7 for mmcblk2 (eMMC)
      mmc bootpart enable 7 0 /dev/mmcblk2
      
    • via JTAG:
      # start with soc-specific position-independent boot firmware binary 
      wget https://dev.gateworks.com/venice/boot_firmware/venice-imx8mp-flash.bin
      # create a 4MB file and copy the position-independent boot firmware to where the BOOT ROM expects it (32K in this case)
      truncate -s 4M firmware.img
      dd if=venice-imx8mp-flash.bin of=firmware.img bs=1k seek=32 conv=notrunc
      # use the mkimage_jtag script to create a JTAG binary that flashes this image and sets the PARTITION_CONFIG register
      ./mkimage_jtag --soc imx8mp --emmc -s --partconf=user \
          firmware.img@user:erase_part:0-8192 \
          > firmware-venice-imx8mp.bin
      
  • IMX8MM: Program boot firmware to boot0:
    • from U-Boot
      # fetch flash.bin boot firmware
      tftpboot $loadaddr $dir/venice-$soc-flash.bin
      # set blkcnt to $filesize/512 (conver to 512 byte blocks)
      setexpr blkcnt $filesize + 0x1ff && setexpr blkcnt $blkcnt / 0x200
      # select the emmc (dev=2) boot0 hardware partition (part=1)
      mmc dev 2 1
      # write to 0K
      mmc write $loadaddr 0x0 $blkcnt
      # set PARTITION_CONFIG to BOOT_ACK=1 BOOT_PARTITION_ENABLE=1 to boot from boot0
      mmc partconf 2 1 1 0
      
    • from Linux
      # fetch flash.bin boot firmware
      wget https://dev.gateworks.com/venice/boot_firmware/venice-imx8mp-flash.bin
      # write it to mmcblk2boot0 at offset 0KB
      echo 0 > /sys/class/block/mmcblk2boot0/force_ro
      dd if=venice-imx8mp-flash.bin of=/dev/mmcblk2boot0 bs=1k seek=0 conv=notrunc
      # set BOOT_PARTITION_ENABLE to 1 (boot0) for mmcblk2 (eMMC)
      mmc bootpart enable 1 0 /dev/mmcblk2
      
    • via JTAG:
      # start with soc-specific position-independent boot firmware binary 
      wget https://dev.gateworks.com/venice/boot_firmware/venice-imx8mp-flash.bin
      # create a 4MB file and copy the position-independent boot firmware to where the BOOT ROM expects it (0K in this case)
      truncate -s 4M firmware.img
      dd if=venice-imx8mp-flash.bin of=firmware.img bs=1k seek=0 conv=notrunc
      # use the mkimage_jtag script to create a JTAG binary that flashes this image and sets the PARTITION_CONFIG register
      ./mkimage_jtag --soc imx8mp --emmc -s --partconf=boot0 \
          firmware.img@boot0:erase_part:0-8192 \
          > firmware-venice-imx8mp.bin
      

The examples above start with the position-independent boot firmware therefore they do not contain the U-Boot environment area which is always stored at the top of the 4MB boundary of the eMMC hardware partition that U-Boot boots from. You can create and update this environment data via:

  • Create environment data:
    • from Gateworks default firmware image:
      wget https://dev.gateworks.com/venice/images/firmware-venice-imx8mm.img
      dd if=firmware-venice-imx8mm.img of=env.bin bs=1k skip=4032 count=128
      
  • Update U-Boot env (to $bootpart) from U-Boot
    tftpboot $loadaddr env.bin && mmc dev $dev $bootpart && mmc write $loadaddr 0x1f80 0x80
    
  • Update U-Boot env to user from Linux
    dd if=env.bin of=/dev/mmcblk2 bs=1k seek=4032 conv=notrunc
    
  • Update U-Boot env to boot0 from Linux
    echo 0 > /sys/class/block/mmcblk2boot0/force_ro
    dd if=env.bin of=/dev/mmcblk2boot0 bs=1k seek=4032 conv=notrunc
    

Legacy Boot Firmware Image

The original Gateworks IMX8MM Boot Firmware (now considered legacy) was installed to the eMMC user hardware partition.

Legacy Venice IMX8MM Boot Firmware Image Map:

start-end len item notes
0x00000000 - 0x00008400 33KiB MBR Partition Table only first 512B used
0x00008400 - 0x00060000 351KiB SPL (spl.bin) Loads and u-boot.itb and transfers control to the ATF
0x00060000 - 0x00FF0000 15MiB U-Boot (u-boot.itb) FIT image containing u-boot, ATF, and fdt
0x00FF0000 - 0x01000000 64KB U-Boot env redundant 32KB env
0x01000000 - Disk Partitions used by the OS

U-Boot Bootloader

Read more on the dedicated bootloader page here: Venice U-Boot Bootloader

Last modified 6 months ago Last modified on 05/14/2024 03:58:44 PM
Note: See TracWiki for help on using the wiki.