Saturday, February 23, 2019

Espressobin - building U-Boot

Continuing in the topic of the previous post - building the Kernel - I look into how Armbian builds U-Boot for the Espressobin.
There is some info on building U-Boot on the wiki but even though I tried to follow it to the letter, the U-Boot I build would never boot. Yet the U-Boot binaries build by Armbian work OK. Also note that there are several board revisions, so you certainly need sufficient new U-Boot or you can run into funny issues.

So, untangling the Armbian build scripts further (see the previous post for some context), let's see how the U-Boot is built:
  • the relevant sources are fetched in lib/ and they are, at time of this this writing:
    • marvel-tools:, branch A3700_utils-armada-18.12
    • marvell-ddr:, branch mv_ddr-armada-18.12
    • ATF:, branch atf-v1.5-armada-18.12
    • U-Boot:, branch u-boot-2018.03-armada-18.12
First the ATF's bl32.bin is built by compile_atf:
  • change into the ATF directory
  • ATF_TARGET_MAP (which is defined in config/sources/mvebu64.conf) is parsed - split by ; into three parts:
    • target_patchdir: (empty)
    • target_files: build/a3700/debug/bl31.bin
  • advanced_patch atf atf-mvebu64 espressobin $target_patchdir next mvebu64-espressobin-next, applies patches from:
    • patch/atf/atf-mvebu64/target_
    • patch/atf/atf-mvebu64/board_espressobin
    • patch/atf/atf-mvebu64/branch_next
    • patch/atf/atf-mvebu64
  • none of the directories exist, so no patches are applied for the Espressobin
  •  make $target_make CROSS_COMPILE="$ATF_COMPILER"
  • atf_custom_postprocess from config/sources/mvebu64.conf is called
  • copy all $target_files - which, for the Espressobin, is just 1 file: build/a3700/debug/bl31.bin - into .tmp/atf-${LINUXFAMILY}-${BOARD}-${BRANCH} ... where it's magicaly found by compile_uboot, yay!
Then U-Boot is built by compile_uboot. It does:
  • change into U-Boot directory
  • UBOOT_TARGET_MAP is read (defined in config/sources/mvebu64.conf), and for each line the loop body is called:
    • for the Espressobin there is only one line in
      UBOOT_TARGET_MAP and so the loop it executed just once with target = "DEVICE_TREE=armada-3720-espressobin ;;flash-image-*.bin"
    • target is split by ; into:
      • target_make: armada-3720-espressobin (luckily the trailing space seems to be dropped)
      • target_patchdir: (empty)
      • target_files: flash-image-*.bin
    • patches are applied by the advanced_patch machinery: advanced_patch "u-boot" "$BOOTPATCHDIR" "$BOARD" "$target_patchdir" "$BRANCH" "${LINUXFAMILY}-${BOARD}-${BRANCH}"
      • BOOTPATCHDIR is u-boot-mvebu64 (lib/
      • so this becomes: advanced_patch u-boot u-boot-mvebu64 espressobin "" next mvebu64-espressobin-next
      • patches are applies searched for in:
        • patch/u-boot/u-boot-mvebu64/target_
        • patch/u-boot/u-boot-mvebu64/board_espressobin
        • patch/u-boot/u-boot-mvebu64/branch_next
        • patch/u-boot/u-boot-mvebu64
      • only patch/u-boot/u-boot-mvebu64 exists and contains currently 1 patch
    • cp -Rv $atftempdir/*.bin .
      • this "recovers" the files built in the ATF step (bl31.bin) and copies them to the u-boot src dir
      • UBOOT_COMPILER="aarch64-linux-gnu-" (lib/
      • BOOTCONFIG="mvebu_espressobin-88f3720_defconfig"
    • patch U-Boot config
      • set LOCALVERSION to "-armbian"
      • setU-Boot env to be stored on a mmc on ext4 in /boot/boot.env
      • build U-Boot: make $target_make $CTHREADS CROSS_COMPILE="$CCACHE $UBOOT_COMPILER"
      • target_make: DEVICE_TREE=armada-3720-espressobin
      • UBOOT_COMPILER="aarch64-linux-gnu-" (lib/
    • uboot_custom_postprocess from config/sources/mvebu64.conf is called - this does the wrapping in ATF
      • change into the ATF source directory
      • builds for all combinations of:
        • clocks=( 600_600 800_800 1000_800 1200_750 )
        • topology=( 512m_1cs_0 512m_2cs_0 1g_2cs_2 1g_1cs_4 2g_2cs_2 1g_1cs_5 2g_2cs_6 )
          • *cs_5 or *cs_6 means DDR4, others are DDR3 (see here)
        • if you build just for one revision, then you need to pick one of the clocks and topology values, for example for the Espressobin V5_0_1 with 2GiB, 2 chips, the values seem to be:
          • clock: 1000_800
          • topology: 2g_2cs_2
        • DDR_TOPOLOGY is set to the suffix after the last _ in topology (e.g. "2")
        • CLOCKSPRESET is set to "CPU_${i%_*}_DDR_${i##*_}", e.g. CPU_1000_DDR_800
        • the actual ATF binaries are built: make MV_DDR_PATH=$SRC/cache/sources/marvell-ddr CROSS_COMPILE=$ATF1 DEBUG=1 USE_COHERENT_MEM=0 LOG_LEVEL=20 SECURE=0 CLOCKSPRESET=$CLOCKSPRESET DDR_TOPOLOGY=$DDR_TOPOLOGY BOOTDEV=SPINOR PARTNUM=0 PLAT=a3700 all fip BL33=$BL33 WTP=$SRC/cache/sources/marvell-tools $CTHREADS CROSS_CM3=$ATF2
          • ATF1=$toolchain/$ATF_COMPILER (set in atf_custom_postprocess)
            • ATF_COMPILER='aarch64-linux-gnu-' (in config/sources/mvebu64.conf)
          • ATF2=arm-linux-gnueabi- (in config/sources/mvebu64.conf)
          • BL33=$ubootdir"/u-boot.bin" (set in atf_custom_postprocess)
        • the resulting files are produced in build/a3700/debug
Whoa... not easy, and the build scripts don't make understanding the flow any easier.

No comments:

Post a Comment