[][Refactor eMMC image of MT7986]

[Description]
Refactor eMMC image of MT7986.
The whole image format is changed:
 - Kernel and rootfs reside in individual partitions.
 - rootfs_data split from rootfs partition using loop device with offset.
 - Upgrading firmware usig tarball with saving config files supported.
 - No recovery partition needed.
 - No GPT partition offset and size restricted.

Important note:
Please select the following packages to make emmc firmware upgrading work:
e2fsprogs mkf2fs blkid blockdev losetup kmod-fs-ext4 kmod-fs-f2fs

[Release-log]
N/A

Change-Id: I9c8c3800ae45c0316a30b2fc0bc825fd71b0f24e
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/5258148
diff --git a/target/linux/mediatek/base-files/lib/upgrade/mmc.sh b/target/linux/mediatek/base-files/lib/upgrade/mmc.sh
new file mode 100644
index 0000000..bd1966c
--- /dev/null
+++ b/target/linux/mediatek/base-files/lib/upgrade/mmc.sh
@@ -0,0 +1,121 @@
+
+# Keep these values be up-to-date with definition in libfstools/rootdisk.c of fstools package
+ROOTDEV_OVERLAY_ALIGN=$((64*1024))
+F2FS_MINSIZE=$((100*1024*1024))
+
+mtk_get_root() {
+	local rootfsdev
+
+	if read cmdline < /proc/cmdline; then
+		case "$cmdline" in
+			*root=*)
+				rootfsdev="${cmdline##*root=}"
+				rootfsdev="${rootfsdev%% *}"
+			;;
+		esac
+
+		echo "${rootfsdev}"
+	fi
+}
+
+mmc_upgrade_tar() {
+	local tar_file="$1"
+	local kernel_dev="$2"
+	local rootfs_dev="$3"
+
+	local board_dir=$(tar tf ${tar_file} | grep -m 1 '^sysupgrade-.*/$')
+	board_dir=${board_dir%/}
+
+	local kernel_length=$( (tar xf $tar_file ${board_dir}/kernel -O | wc -c) 2> /dev/null)
+	local rootfs_length=$( (tar xf $tar_file ${board_dir}/root -O | wc -c) 2> /dev/null)
+
+	[ "${kernel_length}" != 0 ] && {
+		tar xf ${tar_file} ${board_dir}/kernel -O >${kernel_dev}
+	}
+
+	[ "${rootfs_length}" != 0 ] && {
+		tar xf ${tar_file} ${board_dir}/root -O >${rootfs_dev}
+	}
+
+	local rootfs_dev_size=$(blockdev --getsize64 ${rootfs_dev})
+	[ $? -ne 0 ] && return 1
+
+	local rootfs_data_offset=$(((rootfs_length+ROOTDEV_OVERLAY_ALIGN-1)&~(ROOTDEV_OVERLAY_ALIGN-1)))
+	local rootfs_data_size=$((rootfs_dev_size-rootfs_data_offset))
+
+	local loopdev="$(losetup -f)"
+	losetup -o $rootfs_data_offset $loopdev $rootfs_dev || {
+		v "Failed to mount looped rootfs_data."
+		return 1
+	}
+
+	local fstype=ext4
+	local mkfs_arg="-q -L rootfs_data"
+	[ "${rootfs_data_size}" -gt "${F2FS_MINSIZE}" ] && {
+		fstype=f2fs
+		mkfs_arg="-q -l rootfs_data"
+	}
+
+	v "Format new rootfs_data at position ${rootfs_data_offset}."
+	mkfs.${fstype} ${mkfs_arg} ${loopdev}
+	[ $? -ne 0 ] && return 1
+
+	[ -n "$UPGRADE_BACKUP" ] && {
+		mkdir -p /tmp/new_root
+		mount -t ${fstype} ${loopdev} /tmp/new_root && {
+			v "Saving config to rootfs_data at position ${rootfs_data_offset}."
+			mv "$UPGRADE_BACKUP" "/tmp/new_root/$BACKUP_FILE"
+			umount /tmp/new_root
+		}
+	}
+
+	# Cleanup
+	losetup -d ${loopdev} >/dev/null 2>&1
+	sync
+
+	return 0
+}
+
+mtk_mmc_do_upgrade() {
+	local tar_file="$1"
+	local board=$(board_name)
+	local kernel_dev=
+	local rootfs_dev=
+	local cmdline_root="$(mtk_get_root)"
+
+	case "$cmdline_root" in
+	/dev/mmcblk*)
+		rootfs_dev=${cmdline_root}
+		;;
+	PARTLABEL=* | PARTUUID=*)
+		rootfs_dev=$(blkid -t "${cmdline_root}" -o device)
+		[ -z "${rootfs_dev}" -o $? -ne 0 ] && return 1
+		;;
+	*)
+		return 1;
+		;;
+	esac
+
+	case "$board" in
+	*)
+		kernel_dev=$(blkid -t "PARTLABEL=kernel" -o device)
+		[ -z "${kernel_dev}" -o $? -ne 0 ] && return 1
+		;;
+	esac
+
+	# keep sure its unbound
+	losetup --detach-all || {
+		v "Failed to detach all loop devices."
+		sleep 10
+		reboot -f
+	}
+
+	mmc_upgrade_tar "${tar_file}" "${kernel_dev}" "${rootfs_dev}"
+
+	[ $? -ne 0 ] && {
+		v "Upgrade failed."
+		return 1
+	}
+
+	return 0
+}
diff --git a/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-emmc-rfb.dts b/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-emmc-rfb.dts
index df49496..c094abe 100644
--- a/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-emmc-rfb.dts
+++ b/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-2500wan-emmc-rfb.dts
@@ -3,11 +3,11 @@
 #include "mt7986a-pinctrl.dtsi"
 / {
 	model = "MediaTek MT7986a RFB";
-	compatible = "mediatek,mt7986a-2500wan-nor-rfb";
+	compatible = "mediatek,mt7986a-emmc-rfb";
 	chosen {
 		bootargs = "console=ttyS0,115200n1 loglevel=8  \
 				earlycon=uart8250,mmio32,0x11002000 \
-				root=/dev/mmcblk0p7 rootwait rootfstype=squashfs,f2fs";
+				root=PARTLABEL=rootfs rootwait rootfstype=squashfs,f2fs";
 	};
 
 	memory {
diff --git a/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-emmc-rfb.dts b/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-emmc-rfb.dts
index 27bf0b5..f5ec053 100644
--- a/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-emmc-rfb.dts
+++ b/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986a-emmc-rfb.dts
@@ -7,7 +7,7 @@
 	chosen {
 		bootargs = "console=ttyS0,115200n1 loglevel=8  \
 				earlycon=uart8250,mmio32,0x11002000 \
-				root=/dev/mmcblk0p7 rootwait rootfstype=squashfs,f2fs";
+				root=PARTLABEL=rootfs rootwait rootfstype=squashfs,f2fs";
 	};
 
 	memory {
diff --git a/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-2500wan-emmc-rfb.dts b/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-2500wan-emmc-rfb.dts
index a9b420e..d768e45 100644
--- a/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-2500wan-emmc-rfb.dts
+++ b/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-2500wan-emmc-rfb.dts
@@ -7,7 +7,7 @@
 	chosen {
 		bootargs = "console=ttyS0,115200n1 loglevel=8  \
 				earlycon=uart8250,mmio32,0x11002000 \
-				root=/dev/mmcblk0p7 rootwait rootfstype=squashfs,f2fs";
+				root=PARTLABEL=rootfs rootwait rootfstype=squashfs,f2fs";
 	};
 
 	memory {
diff --git a/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-emmc-rfb.dts b/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-emmc-rfb.dts
index 1dfecc3..73f1462 100644
--- a/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-emmc-rfb.dts
+++ b/target/linux/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7986b-emmc-rfb.dts
@@ -7,7 +7,7 @@
 	chosen {
 		bootargs = "console=ttyS0,115200n1 loglevel=8  \
 				earlycon=uart8250,mmio32,0x11002000 \
-				root=/dev/mmcblk0p7 rootwait rootfstype=squashfs,f2fs";
+				root=PARTLABEL=rootfs rootwait rootfstype=squashfs,f2fs";
 	};
 
 	memory {
diff --git a/target/linux/mediatek/image/gen_mt7986_emmc_img.sh b/target/linux/mediatek/image/gen_mt7986_emmc_img.sh
deleted file mode 100755
index d74068c..0000000
--- a/target/linux/mediatek/image/gen_mt7986_emmc_img.sh
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/bin/sh
-
-OUTPUT_FILE=$1
-KERNEL_FILE=$2
-RECOVERY_FILE=$3
-ROOTFS_FILE=$4
-
-BS=512
-
-#RECOVERY_OFFSET= kernel size / BS = 20M / 512 (blocks)
-RECOVERY_OFFSET=40960
-
-#ROOTFS_OFFSET = RECOVERY_OFFSET + (RECOVERY_SIZE / BS)
-#	       = 40960 + (10M  / 512) (blocks)
-ROOTFS_OFFSET=61440
-dd bs="$BS" of="$OUTPUT_FILE" if="$KERNEL_FILE"
-dd bs="$BS" of="$OUTPUT_FILE" if="$RECOVERY_FILE" seek="$RECOVERY_OFFSET"
-dd bs="$BS" of="$OUTPUT_FILE" if="$ROOTFS_FILE" seek="$ROOTFS_OFFSET"
-dd if=/dev/zero of="$OUTPUT_FILE" bs=128k count=1 oflag=append conv=notrunc
diff --git a/target/linux/mediatek/image/mt7986.mk b/target/linux/mediatek/image/mt7986.mk
index 7aac59d..65031a9 100644
--- a/target/linux/mediatek/image/mt7986.mk
+++ b/target/linux/mediatek/image/mt7986.mk
@@ -64,9 +64,11 @@
   DEVICE_MODEL := mt7986a-ax6000-emmc-rfb
   DEVICE_DTS := mt7986a-emmc-rfb
   DEVICE_DTS_DIR := $(DTS_DIR)/mediatek
-  DEVICE_PACKAGES := mkf2fs e2fsprogs kmod-fs-vfat kmod-nls-cp437 kmod-nls-iso8859-1 kmod-mmc
-  IMAGES := sysupgrade-emmc.bin.gz
-  IMAGE/sysupgrade-emmc.bin.gz := sysupgrade-emmc | gzip | append-metadata
+  SUPPORTED_DEVICES := mediatek,mt7986a-emmc-rfb
+  DEVICE_PACKAGES := mkf2fs e2fsprogs blkid blockdev losetup kmod-fs-ext4 \
+		     kmod-mmc kmod-fs-f2fs kmod-fs-vfat kmod-nls-cp437 \
+		     kmod-nls-iso8859-1
+  IMAGE/sysupgrade.bin := sysupgrade-tar | append-metadata
 endef
 TARGET_DEVICES += mt7986a-ax6000-emmc-rfb
 
@@ -209,9 +211,11 @@
   DEVICE_MODEL := mt7986b-ax6000-emmc-rfb
   DEVICE_DTS := mt7986b-emmc-rfb
   DEVICE_DTS_DIR := $(DTS_DIR)/mediatek
-  DEVICE_PACKAGES := mkf2fs e2fsprogs kmod-fs-vfat kmod-nls-cp437 kmod-nls-iso8859-1 kmod-mmc
-  IMAGES := sysupgrade-emmc.bin.gz
-  IMAGE/sysupgrade-emmc.bin.gz := sysupgrade-emmc | gzip | append-metadata
+  SUPPORTED_DEVICES := mediatek,mt7986b-emmc-rfb
+  DEVICE_PACKAGES := mkf2fs e2fsprogs blkid blockdev losetup kmod-fs-ext4 \
+		     kmod-mmc kmod-fs-f2fs kmod-fs-vfat kmod-nls-cp437 \
+		     kmod-nls-iso8859-1
+  IMAGE/sysupgrade.bin := sysupgrade-tar | append-metadata
 endef
 TARGET_DEVICES += mt7986b-ax6000-emmc-rfb
 
diff --git a/target/linux/mediatek/mt7986/base-files/lib/upgrade/platform.sh b/target/linux/mediatek/mt7986/base-files/lib/upgrade/platform.sh
index 2ee99c7..4a1573a 100644
--- a/target/linux/mediatek/mt7986/base-files/lib/upgrade/platform.sh
+++ b/target/linux/mediatek/mt7986/base-files/lib/upgrade/platform.sh
@@ -1,3 +1,5 @@
+RAMFS_COPY_BIN='mkfs.f2fs blkid blockdev'
+
 platform_do_upgrade() {
 	local board=$(board_name)
 
@@ -5,6 +7,9 @@
 	*snand*)
 		nand_do_upgrade "$1"
 		;;
+	*emmc*)
+		mtk_mmc_do_upgrade "$1"
+		;;
 	*)
 		default_do_upgrade "$1"
 		;;
@@ -20,7 +25,8 @@
 	[ "$#" -gt 1 ] && return 1
 
 	case "$board" in
-	*snand*)
+	*snand* |\
+	*emmc*)
 		# tar magic `ustar`
 		magic="$(dd if="$1" bs=1 skip=257 count=5 2>/dev/null)"
 
@@ -42,4 +48,3 @@
 
 	return 0
 }
-