diff --git a/config/boards/numaker-iot-ma35d16f90.csc b/config/boards/numaker-iot-ma35d16f90.csc index a9b92f562e..1a44da41f8 100644 --- a/config/boards/numaker-iot-ma35d16f90.csc +++ b/config/boards/numaker-iot-ma35d16f90.csc @@ -11,20 +11,7 @@ BOOT_FDT_FILE="nuvoton/ma35d1-iot-512m.dtb" BOOT_SCENARIO="blobless" IMAGE_PARTITION_TABLE="msdos" DEFAULT_CONSOLE="serial" +SERIALCON="ttyS0:115200" # Hardware features HAS_VIDEO_OUTPUT="yes" - -function post_family_tweaks__numaker_iot_ma35d16f90() { - display_alert "$BOARD" "Applying NuMaker IoT MA35D16F90 tweaks" "info" - - # Serial console 115200 baud - mkdir -p "$SDCARD/etc/systemd/system/serial-getty@ttyS0.service.d/" - cat <<- EOF > "$SDCARD/etc/systemd/system/serial-getty@ttyS0.service.d/override.conf" - [Service] - ExecStart= - ExecStart=-/sbin/agetty -o '-p -- \\u' 115200 ttyS0 linux - EOF - - return 0 -} diff --git a/config/bootenv/nuvoton-ma35d1.txt b/config/bootenv/nuvoton-ma35d1.txt index ca8baf3599..972d4cfd58 100644 --- a/config/bootenv/nuvoton-ma35d1.txt +++ b/config/bootenv/nuvoton-ma35d1.txt @@ -1,3 +1,2 @@ bootlogo=false console=serial -fdtfile=nuvoton/ma35d1-iot-512m.dtb diff --git a/config/sources/families/nuvoton-ma35d1.conf b/config/sources/families/nuvoton-ma35d1.conf index 0b950a7e7b..3d081ba73b 100644 --- a/config/sources/families/nuvoton-ma35d1.conf +++ b/config/sources/families/nuvoton-ma35d1.conf @@ -11,10 +11,6 @@ # Boot flow: Mask ROM (IBR) -> BL2 (TF-A) -> BL31 -> BL32 (OP-TEE) -> BL33 (U-Boot) -> Linux ARCH="arm64" -# Keep kernel version clean (5.10.140 instead of 5.10.140-vendor-nuvoton-ma35d1) -# Nuvoton expects exact version for compatibility -declare -g LOCALVERSION="" - # Disable BTF - 5.10.y kernel has issues with newer pahole/toolchain declare -g KERNEL_BTF="no" @@ -28,45 +24,20 @@ BOOTPATCHDIR="u-boot-nuvoton-ma35d1" BOOTSOURCE='https://github.com/OpenNuvoton/MA35D1_u-boot-v2020.07.git' BOOTBRANCH='branch:master' BOOTDIR='u-boot-nuvoton-ma35d1' -# MA35D1 uses TF-A (BL2/BL31) + OP-TEE, not U-Boot SPL -# All boot files: header.bin, bl2.bin, bl31.bin, bl2-ma35d1.dtb, tee-header_v2.bin, tee-pager_v2.bin, fip.bin, u-boot.bin 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 ATF_USE_GCC="> 8.0" -declare -g ATF_COMPILER="aarch64-linux-gnu-" 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" -# Fix RWX segment warning with binutils 2.39+ (skip -Wl, prefix for LD flags) declare -g ATF_SKIP_LDFLAGS_WL="yes" -# OP-TEE source from Nuvoton -declare -g OPTEE_SOURCE="https://github.com/OpenNuvoton/MA35D1_optee_os-v3.9.0.git" -declare -g OPTEE_DIR="optee-os-ma35d1" -declare -g OPTEE_BRANCH="branch:master" -declare -g OPTEE_COMPILER="aarch64-linux-gnu-" - -# Host dependencies for OP-TEE build (pycryptodome for signing, pyelftools for ELF parsing) -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() { - display_alert "Fetching OP-TEE source" "for MA35D1" "info" - fetch_from_repo "${OPTEE_SOURCE}" "${OPTEE_DIR}" "${OPTEE_BRANCH}" -} - # DDR configuration DTB - 512MB for IoT board -# Available options: ma35d1-cpu800-wb-512m, ma35d1-cpu1g-wb-512m, etc. -declare -g MA35D1_DDR_DTB="${MA35D1_DDR_DTB:-ma35d1-cpu800-wb-512m}" +MA35D1_DDR_DTB="${MA35D1_DDR_DTB:-ma35d1-cpu800-wb-512m}" # TF-A build: BL2 + BL31 + DTB (FIP is created later in uboot_custom_postprocess) -# DEBUG=1 matches platform.mk default, output goes to build/ma35d1/debug/ -# dtbs target is needed to build DDR configuration DTB 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" LINUXFAMILY="nuvoton-ma35d1" @@ -76,13 +47,7 @@ IMAGE_PARTITION_TABLE="msdos" BOOTSCRIPT="boot-nuvoton-ma35d1.cmd:boot.cmd" BOOTENV_FILE="nuvoton-ma35d1.txt" -# Clean kernel version - disabled for now, causes packaging issues -# Clean kernel version - required for Nuvoton precompiled modules (dcultrafb.ko, ma35d1-vc8000.ko etc.) -# These modules have vermagic "5.10.140" and won't load with suffix -# enable_extension "nuvoton-clean-kernel-version" - case "${BRANCH}" in - vendor) declare -g KERNEL_MAJOR_MINOR="5.10" KERNELSOURCE='https://github.com/OpenNuvoton/MA35D1_linux-5.10.y.git' @@ -90,7 +55,6 @@ case "${BRANCH}" in KERNELPATCHDIR="nuvoton-ma35d1-${BRANCH}" LINUXCONFIG="linux-nuvoton-ma35d1-${BRANCH}" ;; - esac KERNEL_TARGET="vendor" @@ -98,93 +62,59 @@ CPUMIN=180000 CPUMAX=800000 GOVERNOR="ondemand" -family_tweaks() { - : +# 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" } -family_tweaks_bsp() { - : +# 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}" } -# Custom ATF build for MA35D1 - we need BL2 with DTB embedded -# NOTE: atf_custom_postprocess runs BEFORE atftempdir is created! -# We are in the ATF source directory at this point (pwd = $SRC/cache/sources/$ATFSOURCEDIR) +# ATF post-processing: verify build outputs and build fiptool atf_custom_postprocess() { display_alert "Post-processing ATF" "MA35D1" "info" - # We're in the ATF source directory, build output is in ./build/ local atf_src_dir="$(pwd)" - local atf_build_dir="" + local atf_build_dir="${atf_src_dir}/build/ma35d1/debug" - # Debug: show current directory - display_alert "ATF source dir" "${atf_src_dir}" "info" - - # Try release directory first (DEBUG=0), then debug (DEBUG=1) - if [[ -d "${atf_src_dir}/build/ma35d1/release" ]]; then - atf_build_dir="${atf_src_dir}/build/ma35d1/release" - display_alert "Using release build" "${atf_build_dir}" "info" - elif [[ -d "${atf_src_dir}/build/ma35d1/debug" ]]; then - atf_build_dir="${atf_src_dir}/build/ma35d1/debug" - display_alert "Using debug build" "${atf_build_dir}" "info" - else - display_alert "Build directory not found, listing contents" "debug" "warn" - ls -la "${atf_src_dir}/build/" 2>/dev/null || echo "No build directory" - ls -la "${atf_src_dir}/build/ma35d1/" 2>/dev/null || echo "No ma35d1 directory" - exit_with_error "ATF build directory not found in ${atf_src_dir}/build/ma35d1/" + if [[ ! -d "${atf_build_dir}" ]]; then + exit_with_error "ATF build directory not found: ${atf_build_dir}" fi - # List what was built - display_alert "ATF build contents" "$(ls ${atf_build_dir}/*.bin 2>/dev/null | xargs -n1 basename 2>/dev/null || echo 'none')" "info" + # 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" - # Verify bl2.bin and bl31.bin exist - if [[ ! -f "${atf_build_dir}/bl2.bin" ]]; then - exit_with_error "bl2.bin not found in ${atf_build_dir}" - fi + # 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" - if [[ ! -f "${atf_build_dir}/bl31.bin" ]]; then - exit_with_error "bl31.bin not found in ${atf_build_dir}" - fi - - # Look for DTB - local dtb_file="" - if [[ -f "${atf_build_dir}/fdts/${MA35D1_DDR_DTB}.dtb" ]]; then - dtb_file="${atf_build_dir}/fdts/${MA35D1_DDR_DTB}.dtb" - display_alert "DTB found" "${dtb_file}" "info" - else - display_alert "DTB not found in fdts/" "listing available DTBs" "warn" - ls -la "${atf_build_dir}/fdts/"*.dtb 2>/dev/null || echo "No DTB files found" - fi - - # Export the build directory path for use by the target_files copy - # The DTB will be copied via ATF_TARGET_MAP, we just verify it exists here - display_alert "ATF post-processing complete" "bl2.bin + bl31.bin ready" "info" + display_alert "ATF post-processing complete" "bl2.bin + bl31.bin + fiptool ready" "info" } # Compile OP-TEE for MA35D1 -# Called from uboot_custom_postprocess to build OP-TEE before FIP creation compile_optee_ma35d1() { - local optee_src_dir="${SRC}/cache/sources/${OPTEE_DIR}" + 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" - # OP-TEE source is fetched via fetch_sources_tools__ma35d1_fetch_optee() - # Build dependencies are declared via add_host_dependencies__ma35d1_optee_deps() - if [[ ! -d "${optee_src_dir}" ]]; then - exit_with_error "OP-TEE source not found at ${optee_src_dir} - fetch_sources_tools hook may have failed" - fi + [[ -d "${optee_src_dir}" ]] || exit_with_error "OP-TEE source not found at ${optee_src_dir}" - # Determine cross compiler - use system compiler directly local cross_compile="aarch64-linux-gnu-" - # Clean previous build to avoid stale artifacts run_host_command_logged make -C "${optee_src_dir}" clean PLATFORM=nuvoton-MA35D1 2>/dev/null || true - # Build OP-TEE - # Note: Using system cross-compiler - # LDFLAGS: --no-warn-rwx-segments suppresses RWX segment warning in binutils 2.39+ - # NOWERROR=1: Treats warnings as warnings, not errors - # V=1: Verbose output to see actual linker command and errors display_alert "Building OP-TEE" "PLATFORM=nuvoton-MA35D1" "info" run_host_command_logged make -C "${optee_src_dir}" \ CROSS_COMPILE_core="${cross_compile}" \ @@ -194,74 +124,44 @@ compile_optee_ma35d1() { CFG_TEE_CORE_LOG_LEVEL=1 \ LDFLAGS="--no-warn-rwx-segments" \ NOWERROR=1 \ - V=1 \ -j$(nproc) - # Verify output files - if [[ ! -f "${optee_out_dir}/tee-header_v2.bin" ]]; then - exit_with_error "OP-TEE build failed: tee-header_v2.bin not found" - fi - if [[ ! -f "${optee_out_dir}/tee-pager_v2.bin" ]]; then - exit_with_error "OP-TEE build failed: tee-pager_v2.bin not found" - fi + [[ -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" "$(ls -la ${optee_out_dir}/tee-*.bin 2>/dev/null | wc -l) files" "info" + display_alert "OP-TEE built successfully" "MA35D1" "info" } # Post-process U-Boot: create FIP and Nuvoton boot header uboot_custom_postprocess() { display_alert "Creating MA35D1 boot images" "BL2 + OP-TEE + FIP + Header" "info" - # Debug: list available files from ATF - display_alert "U-Boot build directory" "$(pwd)" "info" - display_alert "Available .bin files" "$(ls -la *.bin 2>/dev/null | head -5)" "debug" - - # ATF source directory (for fiptool and DTB) local atf_dir="${SRC}/cache/sources/${ATFDIR}/${ATFBRANCH##*:}" + local atf_build_dir="${atf_dir}/build/ma35d1/debug" local fiptool="${atf_dir}/tools/fiptool/fiptool" - # Find ATF build directory (debug or release) - local atf_build_dir="" - if [[ -d "${atf_dir}/build/ma35d1/debug" ]]; then - atf_build_dir="${atf_dir}/build/ma35d1/debug" - elif [[ -d "${atf_dir}/build/ma35d1/release" ]]; then - atf_build_dir="${atf_dir}/build/ma35d1/release" - fi + # 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 [[ -n "${atf_build_dir}" ]] && [[ -f "${atf_build_dir}/fdts/${MA35D1_DDR_DTB}.dtb" ]]; then - display_alert "Copying DTB from ATF" "${MA35D1_DDR_DTB}.dtb" "info" + 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" - else - display_alert "DTB not found in ATF build" "boot may fail without DDR config" "warn" fi - # Build fiptool if not exists - if [[ ! -x "${fiptool}" ]]; then - display_alert "Building fiptool" "MA35D1" "info" - run_host_command_logged make -C "${atf_dir}/tools/fiptool" HOSTCC=gcc - fi - - # Check required files - show what's available if not found - if [[ ! -f "bl2.bin" ]]; then - display_alert "Files in directory" "$(ls -la)" "warn" - exit_with_error "bl2.bin not found in u-boot build directory" - fi - - if [[ ! -f "bl31.bin" ]]; then - exit_with_error "bl31.bin not found in u-boot build directory" - 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_DIR}/out/arm-plat-nuvoton/core" + 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.bin: bl31 + OP-TEE (tee-header + tee-pager) + u-boot - # Boot flow: BL31 -> BL32 (OP-TEE) -> BL33 (U-Boot) + # Create FIP display_alert "Creating FIP" "bl31 + optee + u-boot" "info" run_host_command_logged "${fiptool}" create \ --soc-fw bl31.bin \ @@ -271,213 +171,103 @@ uboot_custom_postprocess() { fip.bin # Create Nuvoton boot header for SD card boot - # Header format: https://github.com/OpenNuvoton/MA35D1_NuWriter - create_ma35d1_header + 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('