mvebu: cortexa53: uDPU/eDPU convert to dual firmware (A/B)

Methode uDPU and eDPU devices are one of the rare ones with a completely
custom image format being used with custom partition table with F2FS.

Instead of converting the boards to dual firmware (A/B style) and further
expand the already convoluted custom scripts, especially considering that
dual firmware conversion is a breaking change anyway, lets convert to using
the generic eMMC sysupgrade based images.

F2FS ZSTD compression is preserved thanks to fstools now supporting its use
on overlays.

Dual firmware support is implemented via U-Boot scripts so no U-Boot
upgrade is required.

Since there is a partition table layout change, eMMC must be wiped and
reflashed with the generated GPT image from OpenWrt initramfs.

Then on each sysupgrade the firmware slot will be altered.

Instructions:
1. Boot into OpenWrt initramfs
2. Copy openwrt-mvebu-cortexa53-methode_edpu-squashfs-emmc-gpt.img.gz to
the device into /tmp
3. Erase eMMC:
dd if=/dev/zero of=/dev/mmcblk0 bs=1M
4. Extract image
gzip -d /tmp/openwrt-mvebu-cortexa53-methode_edpu-squashfs-emmc-gpt.img.gz
5. Flash image
dd if=/tmp/openwrt-mvebu-cortexa53-methode_edpu-squashfs-emmc-gpt.img of=/dev/mmcblk0
6. Reboot

Signed-off-by: Robert Marko <robert.marko@sartura.hr>
This commit is contained in:
Robert Marko
2026-02-23 17:41:18 +01:00
parent 587a1a8872
commit ada2753d6a
9 changed files with 146 additions and 245 deletions
@@ -0,0 +1,15 @@
. /lib/functions.sh
. /lib/functions/uci-defaults.sh
board_config_update
case "$(board_name)" in
methode,udpu|\
methode,edpu)
ucidef_set_compat_version "2.0"
;;
esac
board_config_flush
exit 0
@@ -0,0 +1,12 @@
#!/bin/sh /etc/rc.common
START=99
boot() {
case $(board_name) in
methode,udpu|\
methode,edpu)
fw_setenv bootcount 0
;;
esac
}
@@ -1,49 +0,0 @@
#
# Copyright (C) 2014-2019 OpenWrt.org
# Copyright (C) 2016 LEDE-Project.org
#
preinit_mount_udpu() {
. /lib/functions.sh
. /lib/upgrade/common.sh
case $(board_name) in
methode,udpu|\
methode,edpu)
# Check which device is detected
[ -b "/dev/mmcblk0" ] && mmcdev="/dev/mmcblk0" || mmcdev="/dev/mmcblk1"
if [ -b "${mmcdev}p4" ]; then
mkdir /misc
mount -o compress_algorithm=zstd -t f2fs ${mmcdev}p4 /misc
[ -f "/misc/$BACKUP_FILE" ] && {
echo "- Restoring configuration files -"
tar xzf "/misc/$BACKUP_FILE" -C /
rm -f "/misc/$BACKUP_FILE"
sync
}
[ -f "/misc/firmware/recovery.itb" ] && {
echo "- Updating /recovery partition -"
mkfs.ext4 -q ${mmcdev}p2 | echo y &> /dev/null
mkdir -p /tmp/recovery
mount ${mmcdev}p2 /tmp/recovery
cp /misc/firmware/recovery.itb /tmp/recovery
[ -f "/misc/firmware/boot.scr" ] && \
cp /misc/firmware/boot.scr /tmp/recovery
sync
umount /tmp/recovery
rm -rf /tmp/recovery
# Replace previous backup with the new one
[ -d "/misc/firmware_old" ] && rm -rf /misc/firmware_old
[ -d "/misc/firmware" ] && mv /misc/firmware /misc/firmware_old
}
fi
# Legacy support - if rootfs was booted, instruct u-boot to keep the current root dev
[ "$(df | grep /dev/root)" ] && fw_setenv root_ok '2'
;;
esac
}
boot_hook_add preinit_main preinit_mount_udpu
@@ -35,7 +35,37 @@ platform_do_upgrade() {
;;
methode,udpu|\
methode,edpu)
platform_do_upgrade_uDPU "$1"
[ "$(rootfs_type)" = "tmpfs" ] && {
local firmware_active="$(fw_printenv -n bootactive)"
case "$firmware_active" in
1)
CI_KERNPART="kernel_2"
CI_ROOTPART="rootfs_2"
fw_setenv bootactive 2
;;
2)
CI_KERNPART="kernel_1"
CI_ROOTPART="rootfs_1"
fw_setenv bootactive 1
;;
esac
}
local root="$(cmdline_get_var root)"
case "$root" in
/dev/mmcblk*p2)
CI_KERNPART="kernel_2"
CI_ROOTPART="rootfs_2"
fw_setenv bootactive 2
;;
/dev/mmcblk*p4)
CI_KERNPART="kernel_1"
CI_ROOTPART="rootfs_1"
fw_setenv bootactive 1
;;
esac
emmc_do_upgrade "$1"
;;
*)
default_do_upgrade "$1"
@@ -54,7 +84,7 @@ platform_copy_config() {
;;
methode,udpu|\
methode,edpu)
platform_copy_config_uDPU
emmc_copy_config
;;
esac
}
@@ -1,162 +0,0 @@
udpu_check_emmc() {
# uDPU uses combined ext4 and f2fs partitions.
# partition layout:
# 1. boot (ext4)
# 2. recovery (ext4)
# 3. rootfs (f2fs)
# 4. misc (f2fs)
# Check which device is available, depending on the board revision
if [ -b "/dev/mmcblk1" ]; then
emmc_dev=/dev/mmcblk1
elif [ -b "/dev/mmcblk0" ]; then
emmc_dev=/dev/mmcblk0
else
echo "Cannot detect eMMC flash, aborting.."
exit 1
fi
}
udpu_part_prep() {
if grep -q "$1" /proc/mounts; then
mounted_part="$(grep -m 1 $1 /proc/mounts | awk '{print $2}')"
umount "$mounted_part"
grep -woq "$mounted_part" /proc/mounts && umount -l "$mounted_part"
fi
}
udpu_do_part_check() {
local emmc_parts="1 2 3 4"
local part_valid="1"
# Check if the block devices exist
for num in ${emmc_parts}; do
[ ! -b ${emmc_dev}p${num} ] && part_valid="0"
done
# If partitions are missing create a new partition table
if [ "$part_valid" != "1" ]; then
printf "Invalid partition table, creating a new one\n"
printf "o\nn\np\n1\n\n+256M\nn\np\n2\n\n+256M\nn\np\n3\n\n+1536M\nn\np\n\n\nw\n" | fdisk -W always $emmc_dev > /dev/null 2>&1
# Format the /misc part right away as we will need it for the firmware
printf "Formating /misc partition, this make take a while..\n"
udpu_part_prep ${emmc_dev}p4
if mkfs.f2fs -q -l misc -O extra_attr,compression ${emmc_dev}p4; then
printf "/misc partition formated successfully\n"
else
printf "/misc partition formatting failed\n"
fi
udpu_do_initial_setup
else
printf "Partition table looks ok\n"
fi
}
udpu_do_misc_prep() {
if ! grep -woq /misc /proc/mounts; then
mkdir -p /misc
# If the mount fails, try to reformat partition
# Leaving possiblity for multiple iterations
if ! mount ${emmc_dev}p4 /misc; then
printf "Error while mounting /misc, trying to reformat..\n"
format_count=0
while [ "$format_count" -lt "1" ]; do
udpu_part_prep ${emmc_dev}p4
mkfs.f2fs -q -l misc -O extra_attr,compression ${emmc_dev}p4
if ! mount ${emmc_dev}p4 /misc; then
umount -l /misc
printf "Failed while mounting /misc\n"
format_count=$((format_count +1))
else
printf "Mounted /misc successfully\n"
break
fi
done
fi
fi
}
udpu_do_initial_setup() {
# Prepare /recovery parition
udpu_part_prep ${emmc_dev}p2
mkfs.ext4 -qF ${emmc_dev}p2 2>&1 /dev/null
# Prepare /boot partition
udpu_part_prep ${emmc_dev}p1
mkfs.ext4 -qF ${emmc_dev}p1 2>&1 /dev/null
# Prepare /root partition
printf "Formating /root partition, this may take a while..\n"
udpu_part_prep ${emmc_dev}p3
mkfs.f2fs -q -l rootfs -O extra_attr,compression ${emmc_dev}p3 && printf "/root partition reformated\n"
}
udpu_do_regular_upgrade() {
# Clean /boot partition - mfks.ext4 is not available in chroot
grep -woq /boot /proc/mounts && umount /boot
mkdir -p /tmp/boot
mount ${emmc_dev}p1 /tmp/boot
rm -rf /tmp/boot/*
# Clean /root partition - mkfs.f2fs is not available in chroot
grep -woq /dev/root /proc/mounts && umount /
mkdir -p /tmp/rootpart
mount ${emmc_dev}p3 /tmp/rootpart
rm -rf /tmp/rootpart/*
}
platform_do_upgrade_uDPU() {
udpu_check_emmc
# Prepare and extract firmware on /misc partition
udpu_do_misc_prep
[ -f "/misc/firmware" ] && rm -r /misc/firmware
mkdir -p /misc/firmware
tar xzf "$1" -C /misc/firmware/
udpu_do_regular_upgrade
printf "Updating /boot partition\n"
if tar xzf /misc/firmware/boot.tgz -C /tmp/boot; then
printf "/boot partition updated successfully\n"
else
printf "/boot partition update failed\n"
fi
sync
printf "Updating /root partition\n"
if tar xzf /misc/firmware/rootfs.tgz -C /tmp/rootpart; then
printf "/root partition updated successfully\n"
else
printf "/root partition update failed\n"
fi
sync
# Saving configuration files over sysupgrade
platform_copy_config_uDPU
# Remove tmp mounts
tmp_parts=$(grep "${emmc_dev}" /proc/mounts | awk '{print $2}')
for part in ${tmp_parts}; do
umount "$part"
# Force umount is necessary
grep -q "${part}" /proc/mounts && umount -l "$part"
done
# Sysupgrade complains about /tmp and /dev, so we can detach them here
umount -l /tmp
umount -l /dev
}
platform_copy_config_uDPU() {
# Config is saved on the /misc partition and copied on the rootfs after the reboot
if [ -f "$UPGRADE_BACKUP" ]; then
cp -f "$UPGRADE_BACKUP" "/misc/$BACKUP_FILE"
sync
fi
}
+1 -1
View File
@@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk
ARCH:=aarch64
BOARDNAME:=Marvell Armada 3700LP (ARM64)
CPU_TYPE:=cortex-a53
FEATURES+=ext4
FEATURES+=ext4 emmc
DEFAULT_PACKAGES+=e2fsprogs ethtool mkf2fs partx-utils
KERNELNAME:=Image dtbs
-13
View File
@@ -136,19 +136,6 @@ define Build/sdcard-img-ext4
83 $(CONFIG_TARGET_ROOTFS_PARTSIZE) $(IMAGE_ROOTFS)
endef
define Build/uDPU-firmware
(rm -fR $@-fw; mkdir -p $@-fw)
$(CP) $(BIN_DIR)/$(KERNEL_INITRAMFS_IMAGE) $@-fw/recovery.itb
$(CP) $(IMAGE_ROOTFS) $@-fw/rootfs.tgz
$(CP) $@-boot.scr $@-fw/boot.scr
$(TAR) -czp --numeric-owner --owner=0 --group=0 --sort=name \
$(if $(SOURCE_DATE_EPOCH),--mtime="@$(SOURCE_DATE_EPOCH)") \
-f $@-fw/boot.tgz -C $@.boot .
$(TAR) -czp --numeric-owner --owner=0 --group=0 --sort=name \
$(if $(SOURCE_DATE_EPOCH),--mtime="@$(SOURCE_DATE_EPOCH)") \
-f $(KDIR_TMP)/$(DEVICE_IMG_PREFIX)-firmware.tgz -C $@-fw .
endef
define Device/FitImage
KERNEL_SUFFIX := -uImage.itb
KERNEL = kernel-bin | libdeflate-gzip | fit gzip $$(KDIR)/image-$$(DEVICE_DTS).dtb
+35 -8
View File
@@ -97,19 +97,46 @@ define Device/marvell_armada-3720-db
endef
TARGET_DEVICES += marvell_armada-3720-db
define Build/methode-gpt-emmc
cp $@ $@.tmp 2>/dev/null || true
ptgen -g -o $@.tmp -l 1024 \
-t 0x2e -N kernel_1 -r -B -p 32M@1M \
-t 0x2e -N rootfs_1 -r -p 1536M@33M \
-t 0x2e -N kernel_2 -r -B -p 32M@1569M \
-t 0x2e -N rootfs_2 -r -p 1536M@1601M
cat $@.tmp >> $@
rm $@.tmp
endef
define Build/append-boot-part
dd if=$@.bootimg bs=32M conv=sync >> $@
endef
define Device/eMMC-methode
DEVICE_DTS_DIR := $(DTS_DIR)/marvell
KERNEL_NAME := Image
KERNEL := kernel-bin
KERNEL_LOADADDR := 0x00800000
DEVICE_PACKAGES += kmod-i2c-pxa kmod-hwmon-lm75 kmod-dsa-mv88e6xxx
DEVICE_COMPAT_VERSION := 2.0
DEVICE_COMPAT_MESSAGE := Partition layout and image format was changed. \
Upgrade requires reinstallation from initramfs.
FILESYSTEMS := squashfs
IMAGES := sysupgrade.bin emmc-gpt.img.gz
IMAGE/sysupgrade.bin := boot-scr | boot-img-ext4 | sysupgrade-tar kernel=$$$$@.bootimg | append-metadata
IMAGE/emmc-gpt.img.gz := methode-gpt-emmc |\
pad-to 1M | boot-scr | boot-img-ext4 | append-boot-part |\
pad-to 33M | append-rootfs |\
gzip
BOOT_SCRIPT := udpu
endef
define Device/methode_udpu
$(call Device/Default-arm64)
$(call Device/eMMC-methode)
$(call Device/FitImage)
DEVICE_VENDOR := Methode
DEVICE_MODEL := micro-DPU (uDPU)
DEVICE_DTS := armada-3720-uDPU
KERNEL_LOADADDR := 0x00800000
DEVICE_PACKAGES += f2fs-tools fdisk kmod-i2c-pxa kmod-hwmon-lm75 kmod-dsa-mv88e6xxx
DEVICE_IMG_NAME = $$(DEVICE_IMG_PREFIX)-$$(2)
FILESYSTEMS := targz
IMAGES := firmware.tgz
IMAGE/firmware.tgz := boot-scr | boot-img-ext4 | uDPU-firmware | append-metadata
BOOT_SCRIPT := udpu
endef
TARGET_DEVICES += methode_udpu
+51 -10
View File
@@ -8,26 +8,67 @@ gpio clear 12; gpio clear 40; gpio clear 45;
# Find eMMC device,
if mmc dev 0; then
setenv mmcdev 0
setenv rootdev 'root=/dev/mmcblk0p3'
elif mmc dev 1; then
setenv mmcdev 1
setenv rootdev 'root=/dev/mmcblk1p3'
fi
# Check if bootactive variable exists and if not, default to 1
if test -z "${bootactive}"; then
setenv bootactive 1
fi
# Check if bootcount variable exists and if not, default to 0
if test -z "${bootcount}"; then
setenv bootcount 0
fi
if itest ${bootcount} > 2; then
if itest ${bootactive} == 2; then
setenv bootactive 1
else
setenv bootactive 2
fi
setenv bootcount 0
fi
# Find A/B firmware to boot
if itest ${bootactive} == 2; then
setenv kernelpart 3
setenv rootfspart 4
else
setenv kernelpart 1
setenv rootfspart 2
fi
setenv rootdev 'root=/dev/mmcblk'${mmcdev}'p'${rootfspart}
# Set the variables if necessary
if test ${kernel_addr_r}; then
setenv kernel_addr_r 0x5000000
fi
setenv console 'rootfs_mount_options.compress_algorithm=zstd'
setenv bootargs ${console} $rootdev rw rootwait
echo 'Booting firmware:' ${bootactive}
load mmc ${mmcdev}:1 ${kernel_addr_r} Image
if itest ${bootcount} == 0; then
setenv bootcount 1
elif itest ${bootcount} == 1; then
setenv bootcount 2
elif itest ${bootcount} == 2; then
setenv bootcount 3
else
setenv bootcount 4
fi
env save
setenv bootargs $rootdev rootwait fstools_overlay_compression_type=zstd
load mmc ${mmcdev}:${kernelpart} ${kernel_addr_r} Image
bootm ${kernel_addr_r}
# If the boot command fails, fallback to recovery image
echo '-- Boot failed, falling back to the recovery image --'
setenv bootargs $console
load mmc ${mmcdev}:2 ${kernel_addr_r} recovery.itb
bootm ${kernel_addr_r}
# If booting fails before kernel is loaded then reboot
# so the bootcount can trigger a slot switch.
echo 'Booting firmware:' ${bootactive} 'failed, rebooting'
reset