# Firmware configuration for Khadas VIM3
#
# This configuration follows the VIM3's GPT partition layout:
# - Bootloader in first sectors
# - Boot partition (FAT32) for kernel/dtb
# - RootFS A partition (squashfs)
# - RootFS B partition (squashfs)
# - Application data partition (f2fs)

define(NERVES_FW_PLATFORM, "vim3")
define(NERVES_FW_ARCHITECTURE, "aarch64")
define(NERVES_FW_AUTHOR, "Dale Anderson | ST8VRT")
define(scriptaddr, "0x1000000")

# Default paths if not specified
define(ROOTFS, "${NERVES_SYSTEM}/images/rootfs.squashfs")

# This configuration file will create an image that has MBR and
# the following layout:
#
# +----------------------------+
# | MBR                        |
# +----------------------------+
# | U-Boot (8 MB - 128 KB)     |
# +----------------------------+
# | U-Boot Env (128 KB)        |
# +----------------------------+
# | Boot partition (32 MB)     |
# +----------------------------+
# | Rootfs A (256 MB)          |
# +----------------------------+
# | Rootfs B (256 MB)          |
# +----------------------------+
# | Application data (rest)    |
# +----------------------------+

# The boot partition contains the kernel and device tree
define(BOOT_PART_OFFSET, 17408)
define(BOOT_PART_COUNT, 262144)

# Let the rootfs have room to grow to fit larger applications
define-eval(ROOTFS_A_PART_OFFSET, "${BOOT_PART_OFFSET} + ${BOOT_PART_COUNT}")
define(ROOTFS_A_PART_COUNT, 524288)
define-eval(ROOTFS_B_PART_OFFSET, "${ROOTFS_A_PART_OFFSET} + ${ROOTFS_A_PART_COUNT}")
define(ROOTFS_B_PART_COUNT, ${ROOTFS_A_PART_COUNT})

# Application data partition
define-eval(APP_PART_OFFSET, "${ROOTFS_B_PART_OFFSET} + ${ROOTFS_B_PART_COUNT}")
define(APP_PART_COUNT, 1048576)

# Block device where the root filesystem resides
define(NERVES_FW_DEVPATH, "/dev/mmcblk0")

# Application partition metadata for nerves_runtime
define(NERVES_FW_APPLICATION_PART0_DEVPATH, "/dev/mmcblk0p4")
define(NERVES_FW_APPLICATION_PART0_FSTYPE, "f2fs")
define(NERVES_FW_APPLICATION_PART0_TARGET, "/data")

# Firmware metadata
meta-product = "Nerves Firmware"
meta-description = "Khadas VIM3"
meta-version = ${NERVES_SDK_VERSION}
meta-platform = ${NERVES_FW_PLATFORM}
meta-architecture = ${NERVES_FW_ARCHITECTURE}
meta-author = ${NERVES_FW_AUTHOR}
meta-vcs-identifier = ${NERVES_FW_VCS_IDENTIFIER}
meta-misc = ${NERVES_FW_MISC}

# File resources
file-resource bootloader {
    host-path = "${NERVES_SYSTEM}/images/u-boot-skip512.bin"
}

file-resource Image {
    host-path = "${NERVES_SYSTEM}/images/Image"
}

file-resource meson-g12b-a311d-khadas-vim3.dtb {
    host-path = "${NERVES_SYSTEM}/images/meson-g12b-a311d-khadas-vim3.dtb"
}

file-resource boot.scr {
    host-path = "${NERVES_SYSTEM}/images/boot.scr"
}

file-resource rootfs.img {
    host-path = ${ROOTFS}
}

mbr mbr {
    # Bootstrap code is injected by post-createfs.sh from mainline U-Boot 2024.01
    bootstrap-code = "247c269414596adb1e09693e179bb6394193149fc6aa5b81fac256d78797c4ab13ea3f2843aa0361b36ca0ca07560349e917e8b0c24331bc0587948d1e58383142785986225ce7d5c887a0d0dda319c7bb01777d44a8394a2fcdd74d250f7e6887d8eea934d57ffd5d1fcd3ac2e6017de778fa2b2034754f014c9c275c1b8fe3f37d8d27520c24af2bf1eaedd7eb6bbe6465ea84995fd49bac70c2088b51eb7ece78a62084cad0afbcba9d93a50852096d3c8e079b62a247d2644f5eb53bdc83b382a3384d73e7092d849cd38ceedcfa2a6a01c6cca30d9f075dfdbc98d93f4b5ce283a9566bb283ef4e567c3d3376679d772d6a1a3b09219806dd30df1c7b3bfeffe4546a96d859e52ed522614b89ffc2b769dcf272fd8a78daba57f63593f53477499e0e21f8f350cd15b1199eb0db5519b8478bb5d103908b5b86c1ee7bf565c59473e68c6636597be8721a984e6fb206b73dbb88414b149cd2d58a4dcaef125e63f9eac92f444517b65fb004ce620a859fc60ee011227ce3f70631c1f64320593c0a226c4e678305c633099595141a35da2815eb4a92cf419800038e4323e7802d0aec7c716f8138a38acd389ee76d781083645a1533"

    partition 0 {
        block-offset = ${BOOT_PART_OFFSET}
        block-count = ${BOOT_PART_COUNT}
        type = 0xc # FAT32
        boot = true
    }
    partition 1 {
        block-offset = ${ROOTFS_A_PART_OFFSET}
        block-count = ${ROOTFS_A_PART_COUNT}
        type = 0x83 # Linux
    }
    partition 2 {
        block-offset = ${ROOTFS_B_PART_OFFSET}
        block-count = ${ROOTFS_B_PART_COUNT}
        type = 0x83 # Linux
    }
    partition 3 {
        block-offset = ${APP_PART_OFFSET}
        block-count = ${APP_PART_COUNT}
        type = 0x83 # Linux
        expand = true
    }
}

# Location where installed firmware information is stored
uboot-environment uboot-env {
    block-offset = 16128
    block-count = 256
}

# This firmware task writes everything to the destination media
task complete {
    on-init {
        mbr_write(mbr)
        uboot_clearenv(uboot-env)
        uboot_setenv(uboot-env, "nerves_fw_devpath", ${NERVES_FW_DEVPATH})
        fat_mkfs(${BOOT_PART_OFFSET}, ${BOOT_PART_COUNT})

        # Invalidate the application data partition so that it is guaranteed to
        # trigger the corrupt filesystem detection code on first boot and get
        # formatted. If this isn't done and an old card is reused, the
        # application data could be in a weird state.
        raw_memset(${APP_PART_OFFSET}, 256, 0xff)
    }

    on-resource bootloader {
        raw_write(1)
    }

    on-resource boot.scr {

        fat_write(${BOOT_PART_OFFSET}, "boot.scr")
    }
    on-resource Image { fat_write(${BOOT_PART_OFFSET}, "Image") }
    on-resource meson-g12b-a311d-khadas-vim3.dtb {
        fat_write(${BOOT_PART_OFFSET}, "meson-g12b-a311d-khadas-vim3.dtb")
    }

    on-resource rootfs.img {
        raw_write(${ROOTFS_A_PART_OFFSET})
    }

    on-finish {
        uboot_setenv(uboot-env, "nerves_fw_active", "a")
        uboot_setenv(uboot-env, "nerves_fw_validated", "1")
        uboot_setenv(uboot-env, "a.nerves_fw_platform", "${NERVES_FW_PLATFORM}")
        uboot_setenv(uboot-env, "a.nerves_fw_architecture", "${NERVES_FW_ARCHITECTURE}")
        uboot_setenv(uboot-env, "a.nerves_fw_version", "${NERVES_SDK_VERSION}")
        uboot_setenv(uboot-env, "a.nerves_fw_application_part0_devpath", ${NERVES_FW_APPLICATION_PART0_DEVPATH})
        uboot_setenv(uboot-env, "a.nerves_fw_application_part0_fstype", ${NERVES_FW_APPLICATION_PART0_FSTYPE})
        uboot_setenv(uboot-env, "a.nerves_fw_application_part0_target", ${NERVES_FW_APPLICATION_PART0_TARGET})
        uboot_setenv(uboot-env, "bootcmd", "if fatload mmc 1:1 ${scriptaddr} boot.scr; then source ${scriptaddr}; fi")

        # Invalidate the application data partition so that it is guaranteed to
        # trigger the corrupt filesystem detection code on first boot and get
        # formatted. If this isn't done and an old SDCard is reused, the
        # application data could be in a weird state.
        raw_memset(${APP_PART_OFFSET}, 256, 0xff)
    }
}

task upgrade.a {
    # This task upgrades the A partition, so require that B is active
    require-uboot-variable(uboot-env, "nerves_fw_active", "b")

    on-init {
    }

    on-resource boot.scr {

        fat_write(${BOOT_PART_OFFSET}, "boot.scr")
    }
    on-resource Image { fat_write(${BOOT_PART_OFFSET}, "Image") }
    on-resource meson-g12b-a311d-khadas-vim3.dtb {
        fat_write(${BOOT_PART_OFFSET}, "meson-g12b-a311d-khadas-vim3.dtb")
    }

    on-resource rootfs.img {
        raw_write(${ROOTFS_A_PART_OFFSET})
    }

    on-finish {
        uboot_setenv(uboot-env, "nerves_fw_active", "a")
        uboot_setenv(uboot-env, "nerves_fw_validated", "0")
        uboot_setenv(uboot-env, "a.nerves_fw_platform", "${NERVES_FW_PLATFORM}")
        uboot_setenv(uboot-env, "a.nerves_fw_architecture", "${NERVES_FW_ARCHITECTURE}")
        uboot_setenv(uboot-env, "a.nerves_fw_version", "${NERVES_SDK_VERSION}")
        uboot_setenv(uboot-env, "a.nerves_fw_application_part0_devpath", ${NERVES_FW_APPLICATION_PART0_DEVPATH})
        uboot_setenv(uboot-env, "a.nerves_fw_application_part0_fstype", ${NERVES_FW_APPLICATION_PART0_FSTYPE})
        uboot_setenv(uboot-env, "a.nerves_fw_application_part0_target", ${NERVES_FW_APPLICATION_PART0_TARGET})
        uboot_setenv(uboot-env, "bootcmd", "if fatload mmc 1:1 ${scriptaddr} boot.scr; then source ${scriptaddr}; fi")
    }

    on-error {
    }
}

task upgrade.b {
    # This task upgrades the B partition, so require that A is active
    require-uboot-variable(uboot-env, "nerves_fw_active", "a")

    on-init {
    }

    on-resource boot.scr {

        fat_write(${BOOT_PART_OFFSET}, "boot.scr")
    }
    on-resource Image { fat_write(${BOOT_PART_OFFSET}, "Image") }
    on-resource meson-g12b-a311d-khadas-vim3.dtb {
        fat_write(${BOOT_PART_OFFSET}, "meson-g12b-a311d-khadas-vim3.dtb")
    }

    on-resource rootfs.img {
        raw_write(${ROOTFS_B_PART_OFFSET})
    }

    on-finish {
        uboot_setenv(uboot-env, "nerves_fw_active", "b")
        uboot_setenv(uboot-env, "nerves_fw_validated", "0")
        uboot_setenv(uboot-env, "b.nerves_fw_platform", "${NERVES_FW_PLATFORM}")
        uboot_setenv(uboot-env, "b.nerves_fw_architecture", "${NERVES_FW_ARCHITECTURE}")
        uboot_setenv(uboot-env, "b.nerves_fw_version", "${NERVES_SDK_VERSION}")
        uboot_setenv(uboot-env, "b.nerves_fw_application_part0_devpath", ${NERVES_FW_APPLICATION_PART0_DEVPATH})
        uboot_setenv(uboot-env, "b.nerves_fw_application_part0_fstype", ${NERVES_FW_APPLICATION_PART0_FSTYPE})
        uboot_setenv(uboot-env, "b.nerves_fw_application_part0_target", ${NERVES_FW_APPLICATION_PART0_TARGET})
        uboot_setenv(uboot-env, "bootcmd", "if fatload mmc 1:1 ${scriptaddr} boot.scr; then source ${scriptaddr}; fi")
    }

    on-error {
    }
}
