realtek: Introduce Plasma Cloud sysupgrade helper
authorHarshal Gohel <[email protected]>
Fri, 11 Jul 2025 15:58:32 +0000 (15:58 +0000)
committerHauke Mehrtens <[email protected]>
Thu, 28 Aug 2025 19:07:57 +0000 (21:07 +0200)
Plasma Cloud devices use a dual-firmware regions/slots boot mechanism. On
APs, the u-boot is "intelligent" and checks the NOR/NAND partitions (kernel
+ rootfs) for corruption via "datachk". If validation fails, the bootloader
automatically switches to the fallback partition.

On Realtek-based switches, this "datachk" helper is not available.
However, the bootloader still supports two firmware regions/slots.

When flashing a new image, the "inactive" partition is written instead of
overwriting the active one. If no "inactive" partition exists but
"firmware1" is present, the bootloader always treats "firmware1" as
fallback. Only after a successful flash is the `u-boot-env` updated to
select the newly written partition.

On reboot, the bootloader loads the kernel from the new partition and
passes `mtdparts` information as the kernel cmdline. The Plasma Cloud
switch device tree does not override this with a `bootargs` property, so
the active partition layout is honored from cmdline.

Since offsets, sizes, and names of partitions match between the device tree
and cmdline (except the inactive slot), properties and nodes such as
`nvmem-cells` or `compatible` remain fully usable.

This mechanism also allows switching back to the old firmware slot.  For
example, if `firmware1` is currently active (`/proc/mtd` shows it), it can
be switched to slot 2 using:

    . /lib/upgrade/upgrade_dualboot.sh
    set_boot_part 2
    reboot

Firmware upgrades use standard `sysupgrade` tarballs, chosen for
compatibility with vendor images. In theory, one can switch between vendor
and OpenWrt with:

    sysupgrade -n /tmp/*-squashfs-sysupgrade.bin

Note: configuration files must not be preserved, as they are not compatible
with vanilla OpenWrt.

Signed-off-by: Harshal Gohel <[email protected]>
Signed-off-by: Sharadanand Karanjkar <[email protected]>
Link: https://github.com/openwrt/openwrt/pull/19362
Signed-off-by: Hauke Mehrtens <[email protected]>
target/linux/realtek/base-files/lib/upgrade/upgrade_dualboot_plasmacloud.sh [new file with mode: 0644]

diff --git a/target/linux/realtek/base-files/lib/upgrade/upgrade_dualboot_plasmacloud.sh b/target/linux/realtek/base-files/lib/upgrade/upgrade_dualboot_plasmacloud.sh
new file mode 100644 (file)
index 0000000..0f37995
--- /dev/null
@@ -0,0 +1,68 @@
+set_boot_part() {
+       local part_num="$1"
+       local setenv_script="/tmp/fw_env_upgrade"
+       local board=$(board_name)
+
+       case "$board" in
+       *)
+               echo "${board} is not supported for dual boot" 1>&2
+               return 1
+               ;;
+       esac
+
+       # store u-boot env changes
+       mkdir -p /var/lock
+       cat $setenv_script
+       fw_setenv -s $setenv_script || {
+               echo "failed to update U-Boot environment"
+               return 1
+       }
+}
+
+platform_do_upgrade_dualboot_plasmacloud() {
+       local primary_firmware_mtd
+       local restore_backup
+       local next_boot_part
+       local tar_file="$1"
+       local inactive_mtd
+       local board_dir
+
+       inactive_mtd="$(find_mtd_index $PART_NAME)"
+       if [ -z "$inactive_mtd" ]; then
+               # Handle case when u-boot-env is not correctly written and we
+               # are running from initramfs. Only install it in the "firmware1"
+               # partition
+               PART_NAME=firmware1
+               inactive_mtd="$(find_mtd_index $PART_NAME)"
+       fi
+
+       if [ -z "$inactive_mtd" ]; then
+               echo "Cannot find \"firmware1\" nor \"${$PART_NAME}\" partition to work with. Abort!" 2>&1
+               return 1
+       fi
+
+       # identify "inactive" slot id based on the expected partition id
+       # of the primary ("firmware1") slot
+       case "$(board_name)" in
+       *)
+               echo "failed to detect primary firmware mtd partition for board" 2>&1
+               return 1
+               ;;
+       esac
+
+       if [ "$inactive_mtd" = "$primary_firmware_mtd" ]; then
+               next_boot_part="1"
+       else
+               next_boot_part="2"
+       fi
+
+       [ -n "$UPGRADE_BACKUP" ] && restore_backup="${MTD_CONFIG_ARGS} -j ${UPGRADE_BACKUP}"
+
+       # write selected firmware slot
+       board_dir=$(tar tf $tar_file | grep -m 1 '^sysupgrade-.*/$')
+       board_dir=${board_dir%/}
+       tar -xf $tar_file ${board_dir}/kernel ${board_dir}/root -O | mtd $restore_backup write - $PART_NAME
+
+       # update u-boot-env to select new firmware slot
+       set_boot_part "$next_boot_part"
+}