# # SPDX-License-Identifier: GPL-2.0 # # Copyright (c) 2013-2026 Igor Pecovnik, igor@armbian.com # # This file is a part of the Armbian Build Framework # https://github.com/armbian/build/ # # Nuvoton MA35D1 SoC family - ARM Cortex-A35 dual-core + Cortex-M4 # Boot flow: Mask ROM (IBR) -> BL2 (TF-A) -> BL31 -> BL32 (OP-TEE) -> BL33 (U-Boot) -> Linux declare -g ARCH="arm64" # Disable BTF - 5.10.y kernel has issues with newer pahole/toolchain declare -g KERNEL_BTF="no" # Use NetworkManager for network configuration declare -g NETWORKING_STACK="network-manager" declare -g ATF_PLAT="ma35d1" declare -g BOOTDELAY=1 declare -g BOOTPATCHDIR="u-boot-nuvoton-ma35d1" # U-Boot source from Nuvoton declare -g BOOTSOURCE='https://github.com/OpenNuvoton/MA35D1_u-boot-v2020.07.git' declare -g BOOTBRANCH='branch:master' declare -g BOOTDIR='u-boot-nuvoton-ma35d1' declare -g UBOOT_TARGET_MAP=";;u-boot.bin header.bin fip.bin bl2.bin bl31.bin bl2-ma35d1.dtb tee-header_v2.bin tee-pager_v2.bin" # TF-A source from Nuvoton declare -g ATFSOURCE="https://github.com/OpenNuvoton/MA35D1_arm-trusted-firmware-v2.3.git" declare -g ATFDIR="arm-trusted-firmware-ma35d1" declare -g ATFBRANCH="branch:master" declare -g ATFPATCHDIR="atf-nuvoton-ma35d1" declare -g ATF_SKIP_LDFLAGS_WL="yes" # DDR configuration DTB - 512MB for IoT board MA35D1_DDR_DTB="${MA35D1_DDR_DTB:-ma35d1-cpu800-wb-512m}" # TF-A build: BL2 + BL31 + DTB (FIP is created later in uboot_custom_postprocess) declare -g ATF_TARGET_MAP="PLAT=ma35d1 DEBUG=1 DTB_FILE_NAME=${MA35D1_DDR_DTB}.dtb bl2 bl31 dtbs;;build/ma35d1/debug/bl2.bin build/ma35d1/debug/bl31.bin build/ma35d1/debug/fdts/${MA35D1_DDR_DTB}.dtb:bl2-ma35d1.dtb" declare -g LINUXFAMILY="nuvoton-ma35d1" declare -g IMAGE_PARTITION_TABLE="msdos" # Boot script for loading kernel/initrd/dtb from partition declare -g BOOTSCRIPT="boot-nuvoton-ma35d1.cmd:boot.cmd" declare -g BOOTENV_FILE="nuvoton-ma35d1.txt" case "${BRANCH}" in vendor) declare -g KERNEL_MAJOR_MINOR="5.10" declare -g KERNELSOURCE='https://github.com/OpenNuvoton/MA35D1_linux-5.10.y.git' declare -g KERNELBRANCH="branch:master" declare -g KERNELPATCHDIR="nuvoton-ma35d1-${BRANCH}" declare -g LINUXCONFIG="linux-nuvoton-ma35d1-${BRANCH}" ;; esac declare -g KERNEL_TARGET="vendor" declare -g CPUMIN=180000 declare -g CPUMAX=800000 declare -g GOVERNOR="ondemand" # Host dependencies for OP-TEE build function add_host_dependencies__ma35d1_optee_deps() { display_alert "Adding MA35D1 OP-TEE host dependencies" "python3-pycryptodome python3-pyelftools" "info" declare -g EXTRA_BUILD_DEPS="${EXTRA_BUILD_DEPS} python3-pycryptodome python3-pyelftools" } # Fetch OP-TEE source using Armbian's fetch_from_repo mechanism function fetch_sources_tools__ma35d1_fetch_optee() { local optee_source="https://github.com/OpenNuvoton/MA35D1_optee_os-v3.9.0.git" local optee_dir="optee-os-ma35d1" local optee_branch="branch:master" display_alert "Fetching OP-TEE source" "for MA35D1" "info" fetch_from_repo "${optee_source}" "${optee_dir}" "${optee_branch}" } # ATF post-processing: verify build outputs and build fiptool function atf_custom_postprocess() { display_alert "Post-processing ATF" "MA35D1" "info" local atf_src_dir="$(pwd)" local atf_build_dir="${atf_src_dir}/build/ma35d1/debug" if [[ ! -d "${atf_build_dir}" ]]; then exit_with_error "ATF build directory not found: ${atf_build_dir}" fi # Verify required files [[ -f "${atf_build_dir}/bl2.bin" ]] || exit_with_error "bl2.bin not found in ${atf_build_dir}" [[ -f "${atf_build_dir}/bl31.bin" ]] || exit_with_error "bl31.bin not found in ${atf_build_dir}" [[ -f "${atf_build_dir}/fdts/${MA35D1_DDR_DTB}.dtb" ]] || exit_with_error "DTB ${MA35D1_DDR_DTB}.dtb not found" # Build fiptool for use in uboot_custom_postprocess display_alert "Building fiptool" "MA35D1" "info" run_host_command_logged make -C "${atf_src_dir}/tools/fiptool" HOSTCC=gcc [[ -x "${atf_src_dir}/tools/fiptool/fiptool" ]] || exit_with_error "fiptool build failed" display_alert "ATF post-processing complete" "bl2.bin + bl31.bin + fiptool ready" "info" } # Post-process U-Boot: create FIP and Nuvoton boot header function uboot_custom_postprocess() { # Compile OP-TEE for MA35D1 (defined inside for correct hashing) function compile_optee_ma35d1() { local optee_src_dir="${SRC}/cache/sources/optee-os-ma35d1" local optee_out_dir="${optee_src_dir}/out/arm-plat-nuvoton/core" display_alert "Compiling OP-TEE" "MA35D1" "info" [[ -d "${optee_src_dir}" ]] || exit_with_error "OP-TEE source not found at ${optee_src_dir}" local cross_compile="aarch64-linux-gnu-" # Check if linker supports --no-warn-rwx-segments (binutils 2.39+) # Workaround for ubuntu:jammy older toolchain local ldflags="" if ${cross_compile}ld --help 2>&1 | grep -q "no-warn-rwx-segments"; then ldflags="--no-warn-rwx-segments" fi run_host_command_logged make -C "${optee_src_dir}" clean PLATFORM=nuvoton-MA35D1 2>/dev/null || true display_alert "Building OP-TEE" "PLATFORM=nuvoton-MA35D1" "info" run_host_command_logged make -C "${optee_src_dir}" \ CROSS_COMPILE_core="${cross_compile}" \ CROSS_COMPILE_ta_arm64="${cross_compile}" \ PLATFORM=nuvoton-MA35D1 \ CFG_ARM64_core=y \ CFG_TEE_CORE_LOG_LEVEL=1 \ LDFLAGS="${ldflags}" \ NOWERROR=1 \ -j$(nproc) [[ -f "${optee_out_dir}/tee-header_v2.bin" ]] || exit_with_error "OP-TEE build failed: tee-header_v2.bin not found" [[ -f "${optee_out_dir}/tee-pager_v2.bin" ]] || exit_with_error "OP-TEE build failed: tee-pager_v2.bin not found" display_alert "OP-TEE built successfully" "MA35D1" "info" } display_alert "Creating MA35D1 boot images" "BL2 + OP-TEE + FIP + Header" "info" local atf_dir="${SRC}/cache/sources/${ATFDIR}/${ATFBRANCH##*:}" local atf_build_dir="${atf_dir}/build/ma35d1/debug" local fiptool="${atf_dir}/tools/fiptool/fiptool" # Verify fiptool exists (built in atf_custom_postprocess) [[ -x "${fiptool}" ]] || exit_with_error "fiptool not found at ${fiptool}" # Copy DTB from ATF build if not already present if [[ ! -f "bl2-ma35d1.dtb" ]] && [[ -f "${atf_build_dir}/fdts/${MA35D1_DDR_DTB}.dtb" ]]; then cp "${atf_build_dir}/fdts/${MA35D1_DDR_DTB}.dtb" "bl2-ma35d1.dtb" fi # Verify required files [[ -f "bl2.bin" ]] || exit_with_error "bl2.bin not found" [[ -f "bl31.bin" ]] || exit_with_error "bl31.bin not found" [[ -f "bl2-ma35d1.dtb" ]] || exit_with_error "bl2-ma35d1.dtb not found" # Build OP-TEE compile_optee_ma35d1 # Copy OP-TEE binaries local optee_out_dir="${SRC}/cache/sources/optee-os-ma35d1/out/arm-plat-nuvoton/core" cp "${optee_out_dir}/tee-header_v2.bin" . cp "${optee_out_dir}/tee-pager_v2.bin" . # Create FIP display_alert "Creating FIP" "bl31 + optee + u-boot" "info" run_host_command_logged "${fiptool}" create \ --soc-fw bl31.bin \ --tos-fw tee-header_v2.bin \ --tos-fw-extra1 tee-pager_v2.bin \ --nt-fw u-boot.bin \ fip.bin # Create Nuvoton boot header for SD card boot display_alert "Creating Nuvoton boot header" "SD card" "info" python3 <<- 'HEADER_SCRIPT' import struct import os import binascii HEADER_VERSION = 0x20210107 BL2_ENTRY = 0x28000000 BL2_DTB_LOAD = 0x28023000 BL2_LOAD = 0x28000000 IMG_TYPE_DATA = 3 IMG_TYPE_EXEC = 4 dtb_offset = 0x20000 bl2_offset = 0x30000 bl2_size = os.path.getsize('bl2.bin') dtb_size = os.path.getsize('bl2-ma35d1.dtb') if os.path.exists('bl2-ma35d1.dtb') else 0 header = bytearray(512) struct.pack_into('