[][openwrt-24][common][bsp][Add initial support for openwrt master filogic target]
[Description]
Add initial support for filogic target from openwrt master
[Release-log]
N/A
Change-Id: Ib9d44bdf74b05dc445679001e988b2f1fb8d05b6
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/9273335
diff --git a/master/files/package/mtk/reset-boot-count/Makefile b/master/files/package/mtk/reset-boot-count/Makefile
new file mode 100644
index 0000000..83fbf13
--- /dev/null
+++ b/master/files/package/mtk/reset-boot-count/Makefile
@@ -0,0 +1,38 @@
+#
+# Copyright (C) 2008-2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_NAME:=reset-boot-count
+PKG_RELEASE:=1
+PKG_LICENSE:=BSD-3-Clause
+
+include $(INCLUDE_DIR)/package.mk
+
+define KernelPackage/reset-boot-count
+ SUBMENU:=Other modules
+ TITLE:=Reset dual-boot boot counter for MediaTek platform
+ FILES:=$(PKG_BUILD_DIR)/reset-boot-count.ko
+ KCONFIG:=
+endef
+
+define KernelPackage/reset-boot-count/description
+ This is used to reset dual-boot boot retry counter to indicate that the
+ system has booted up successfully
+endef
+
+define Build/Compile
+ $(KERNEL_MAKE) M="$(PKG_BUILD_DIR)" modules
+endef
+
+define KernelPackage/reset-boot-count/install
+ $(INSTALL_DIR) $(1)/etc/init.d
+ $(INSTALL_BIN) ./files/reset-boot-count.init $(1)/etc/init.d/reset-boot-count
+endef
+
+$(eval $(call KernelPackage,reset-boot-count))
diff --git a/master/files/package/mtk/reset-boot-count/files/reset-boot-count.init b/master/files/package/mtk/reset-boot-count/files/reset-boot-count.init
new file mode 100644
index 0000000..257f122
--- /dev/null
+++ b/master/files/package/mtk/reset-boot-count/files/reset-boot-count.init
@@ -0,0 +1,13 @@
+#!/bin/sh /etc/rc.common
+# Copyright (C) 2024 All Rights Reserved.
+# Author: Weijie Gao <weijie.gao@mediatek.com>
+
+START=99
+boot() {
+ local enabled=$([ -f /sys/firmware/devicetree/base/mediatek,reset-boot-count ] && echo Y)
+
+ if [ x"${enabled}" = xY ]; then
+ modprobe reset-boot-count
+ echo 1 > /proc/reset_boot_count
+ fi
+}
diff --git a/master/files/package/mtk/reset-boot-count/src/Makefile b/master/files/package/mtk/reset-boot-count/src/Makefile
new file mode 100644
index 0000000..4aeb180
--- /dev/null
+++ b/master/files/package/mtk/reset-boot-count/src/Makefile
@@ -0,0 +1,2 @@
+
+obj-m := reset-boot-count.o
diff --git a/master/files/package/mtk/reset-boot-count/src/reset-boot-count.c b/master/files/package/mtk/reset-boot-count/src/reset-boot-count.c
new file mode 100644
index 0000000..6a7f220
--- /dev/null
+++ b/master/files/package/mtk/reset-boot-count/src/reset-boot-count.c
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2024 MediaTek Inc. All rights reserved.
+ *
+ * Helper for resetting boot count of A/B boot systems
+ *
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/arm-smccc.h>
+
+#define RBC "reset_boot_count"
+
+#define MTK_SIP_READ_NONRST_REG 0xC2000550
+#define MTK_SIP_WRITE_NONRST_REG 0xC2000551
+
+static struct proc_dir_entry *rbc_entry;
+
+static bool dual_boot_get_boot_count(u32 *retslot, u32 *retcnt)
+{
+ struct arm_smccc_res res = {0};
+ u32 val, slot;
+ s8 neg, pos;
+
+ arm_smccc_smc(MTK_SIP_READ_NONRST_REG, 0, 0, 0, 0, 0, 0, 0, &res);
+
+ val = (u32)res.a0;
+
+ /* slot: val[31..24] = -slot, val[23..16] = slot */
+ pos = (val >> 16) & 0xff;
+ neg = (val >> 24) & 0xff;
+
+ if (!(pos >= 0 && neg <= 0 && pos + neg == 0)) {
+ pr_debug("slot of boot count is invalid\n");
+ goto err;
+ }
+
+ slot = pos;
+
+ /* count: val[15..8] = -count, val[7..0] = count */
+ pos = val & 0xff;
+ neg = (val >> 8) & 0xff;
+
+ if (!(pos >= 0 && neg <= 0 && pos + neg == 0)) {
+ pr_debug("count of boot count is invalid\n");
+ goto err;
+ }
+
+ if (retslot)
+ *retslot = slot;
+
+ if (retcnt)
+ *retcnt = pos;
+
+ return true;
+
+err:
+ if (retslot)
+ *retslot = 0;
+
+ if (retcnt)
+ *retcnt = 0;
+
+ return false;
+}
+
+static void dual_boot_set_boot_count(u32 slot, u32 count)
+{
+ struct arm_smccc_res res = {0};
+ u32 val;
+ s32 neg;
+
+ if (slot > 127 || count > 127)
+ return;
+
+ neg = -count;
+ val = count | ((neg << 8) & 0xff00);
+
+ neg = -slot;
+ val = val | ((uint32_t)slot << 16) | ((neg << 24) & 0xff000000);
+
+ arm_smccc_smc(MTK_SIP_WRITE_NONRST_REG, 0, val, 0, 0, 0, 0, 0, &res);
+}
+
+static int rbc_display(struct seq_file *seq, void *v)
+{
+ return 0;
+}
+
+static int rbc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, rbc_display, inode->i_private);
+}
+
+static ssize_t rbc_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *pos)
+{
+ u32 slot;
+
+ dual_boot_get_boot_count(&slot, NULL);
+ dual_boot_set_boot_count(slot, 0);
+
+ pr_info("Boot count reset\n");
+
+ return count;
+}
+
+static const struct proc_ops rbc_fops = {
+ .proc_open = rbc_open,
+ .proc_read = seq_read,
+ .proc_write = rbc_write,
+ .proc_lseek = seq_lseek,
+ .proc_release = single_release,
+};
+
+static int __init rbc_init(void)
+{
+ rbc_entry = proc_create(RBC, 0200, NULL, &rbc_fops);
+
+ if (!rbc_entry)
+ pr_err("failed to create proc entry " RBC);
+
+ return 0;
+}
+
+static void __exit rbc_exit(void)
+{
+ remove_proc_entry(RBC, NULL);
+}
+
+module_init(rbc_init);
+module_exit(rbc_exit);
+
+MODULE_AUTHOR("Weijie Gao <weijie.gao@mediatek.com>");
+MODULE_DESCRIPTION("Kernel module for resetting boot count of A/B boot systems");
+MODULE_LICENSE("GPL");
diff --git a/master/files/package/system/fstools/patches/0001-add-support-for-dual-boot.patch b/master/files/package/system/fstools/patches/0001-add-support-for-dual-boot.patch
new file mode 100644
index 0000000..53d68b6
--- /dev/null
+++ b/master/files/package/system/fstools/patches/0001-add-support-for-dual-boot.patch
@@ -0,0 +1,570 @@
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -5,6 +5,10 @@ ADD_DEFINITIONS(-Os -ggdb -Wall -Werror
+
+ SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
+
++ADD_LIBRARY(fstools-bootparam SHARED
++ boot_param.c)
++INSTALL(TARGETS fstools-bootparam LIBRARY DESTINATION lib)
++
+ ADD_LIBRARY(fstools SHARED
+ libfstools/common.c
+ libfstools/snapshot.c
+@@ -18,7 +22,7 @@ ADD_LIBRARY(fstools SHARED
+ libfstools/rootdisk.c
+ libfstools/partname.c
+ libfstools/find.c)
+-TARGET_LINK_LIBRARIES(fstools ubox)
++TARGET_LINK_LIBRARIES(fstools ubox fstools-bootparam)
+ INSTALL(TARGETS fstools LIBRARY DESTINATION lib)
+
+ ADD_LIBRARY(blkid-tiny SHARED
+@@ -80,9 +84,9 @@ INSTALL(TARGETS blockd RUNTIME DESTINATI
+ ADD_EXECUTABLE(block block.c probe.c probe-libblkid.c)
+ IF(DEFINED CMAKE_UBIFS_EXTROOT)
+ ADD_DEFINITIONS(-DUBIFS_EXTROOT)
+- TARGET_LINK_LIBRARIES(block blkid-tiny dl uci ubox ubus blobmsg_json ubi-utils ${json})
++ TARGET_LINK_LIBRARIES(block blkid-tiny fstools-bootparam dl uci ubox ubus blobmsg_json ubi-utils ${json})
+ ELSE(DEFINED CMAKE_UBIFS_EXTROOT)
+- TARGET_LINK_LIBRARIES(block blkid-tiny dl uci ubox ubus blobmsg_json ${json})
++ TARGET_LINK_LIBRARIES(block blkid-tiny fstools-bootparam dl uci ubox ubus blobmsg_json ${json})
+ ENDIF(DEFINED CMAKE_UBIFS_EXTROOT)
+ INSTALL(TARGETS block RUNTIME DESTINATION sbin)
+
+--- a/block.c
++++ b/block.c
+@@ -45,6 +45,7 @@
+ #include <libubus.h>
+
+ #include "probe.h"
++#include "boot_param.h"
+
+ #define AUTOFS_MOUNT_PATH "/tmp/run/blockd/"
+
+@@ -87,6 +88,9 @@ static LIST_HEAD(devices);
+ static int anon_mount, anon_swap, auto_mount, auto_swap, check_fs;
+ static unsigned int delay_root;
+
++static char *hide_block_devs[3];
++static uint32_t num_hide_block_devs;
++
+ enum {
+ CFG_ANON_MOUNT,
+ CFG_ANON_SWAP,
+@@ -557,9 +561,12 @@ static struct probe_info* _probe_path(ch
+ return pr;
+ }
+
++static char* find_mount_point(char *block);
++
+ static int _cache_load(const char *path)
+ {
+ int gl_flags = GLOB_NOESCAPE | GLOB_MARK;
++ uint32_t i;
+ int j;
+ glob_t gl;
+
+@@ -568,8 +575,30 @@ static int _cache_load(const char *path)
+
+ for (j = 0; j < gl.gl_pathc; j++) {
+ struct probe_info *pr = _probe_path(gl.gl_pathv[j]);
+- if (pr)
++ bool skip_curr = false;
++
++ if (pr) {
++ char *mp = find_mount_point(pr->dev);
++ if (mp) {
++ /* Skip blocks mounted as root or overlay */
++ if (!strcmp(mp, "/rom") ||
++ !strcmp(mp, "/overlay"))
++ continue;
++ }
++
++ for (i = 0; i < num_hide_block_devs; i++) {
++ /* Skip blocks used for dual boot */
++ if (!strcmp(hide_block_devs[i], pr->dev)) {
++ skip_curr = true;
++ break;
++ }
++ }
++
++ if (skip_curr)
++ continue;
++
+ list_add_tail(&pr->list, &devices);
++ }
+ }
+
+ globfree(&gl);
+@@ -1376,6 +1405,15 @@ static int find_block_ubi(libubi_t libub
+ int dev_num;
+ int vol_id;
+ int err = -1;
++ char rootfs_data_dev[127];
++
++ if (!strcmp(name, "rootfs_data")) {
++ read_boot_param_string("boot-rootfs_data-part", rootfs_data_dev,
++ sizeof(rootfs_data_dev));
++
++ if (rootfs_data_dev[0])
++ name = rootfs_data_dev;
++ }
+
+ err = find_ubi_vol(libubi, name, &dev_num, &vol_id);
+ if (!err)
+@@ -1936,6 +1974,26 @@ static int main_swapoff(int argc, char *
+ return 0;
+ }
+
++static bool add_hide_block_dev(char *path)
++{
++ if (num_hide_block_devs >= ARRAY_SIZE(hide_block_devs))
++ return false;
++
++ hide_block_devs[num_hide_block_devs++] = path;
++ return true;
++}
++
++static void hide_boot_param_dev(const char *name)
++{
++ char *path;
++
++ path = boot_param_get_dev(name);
++ if (path) {
++ if (!add_hide_block_dev(path))
++ free(path);
++ }
++}
++
+ int main(int argc, char **argv)
+ {
+ char *base = basename(*argv);
+@@ -1945,6 +2003,8 @@ int main(int argc, char **argv)
+ ulog_open(-1, -1, "block");
+ ulog_threshold(LOG_NOTICE);
+
++ hide_boot_param_dev("rootfs_data-part");
++
+ if (!strcmp(base, "swapon"))
+ return main_swapon(argc, argv);
+
+--- a/boot_param.c
++++ b/boot_param.c
+@@ -0,0 +1,244 @@
++/* SPDX-License-Identifier: BSD-3-Clause */
++/*
++ * Copyright (C) 2024 MediaTek Inc. All rights reserved.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ */
++
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <stdio.h>
++#include <string.h>
++#include <dirent.h>
++#include <fcntl.h>
++#include <unistd.h>
++#include <glob.h>
++#include <dlfcn.h>
++
++#include <blkid/blkid.h>
++#include <libubox/ulog.h>
++#include "boot_param.h"
++
++#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
++
++#define BOOT_PARAM_STR_MAX_LEN 256
++
++static struct {
++ bool loaded;
++ blkid_probe (*new_probe_from_filename)(const char *);
++ int (*do_safeprobe)(blkid_probe);
++ int (*probe_lookup_value)(blkid_probe, const char *, const char **, size_t *);
++ void (*free_probe)(blkid_probe);
++ int (*probe_enable_partitions)(blkid_probe, int);
++ int (*probe_set_partitions_flags)(blkid_probe, int);
++} libblkid = {};
++
++bool read_boot_param_bool(const char *name)
++{
++ char path[BOOT_PARAM_STR_MAX_LEN];
++ FILE *f;
++
++ snprintf(path, sizeof(path),
++ "/sys/firmware/devicetree/base/mediatek,%s", name);
++
++ f = fopen(path, "rb");
++ if (!f)
++ return false;
++
++ fclose(f);
++
++ return true;
++}
++
++int read_boot_param_string(const char *name, char *val, size_t maxsize)
++{
++ char path[BOOT_PARAM_STR_MAX_LEN];
++ size_t len;
++ FILE *f;
++
++ snprintf(path, sizeof(path),
++ "/sys/firmware/devicetree/base/mediatek,%s", name);
++
++ f = fopen(path, "rb");
++ if (!f) {
++ val[0] = 0;
++ return -1;
++ }
++
++ len = fread(val, 1, maxsize, f);
++ fclose(f);
++
++ while (len > 0) {
++ if (val[len - 1] != '\n' && val[len - 1] != '\r')
++ break;
++
++ len--;
++ }
++
++ if (len < maxsize)
++ val[len] = 0;
++
++ return len;
++}
++
++static bool load_libblkid(void)
++{
++ void *lib;
++
++ if (libblkid.loaded)
++ return true;
++
++ lib = dlopen("libblkid.so", RTLD_GLOBAL);
++
++ if (!lib)
++ lib = dlopen("libblkid.so.1", RTLD_GLOBAL);
++
++ if (!lib)
++ return false;
++
++ libblkid.new_probe_from_filename = dlsym(lib, "blkid_new_probe_from_filename");
++ if (!libblkid.new_probe_from_filename)
++ return false;
++
++ libblkid.do_safeprobe = dlsym(lib, "blkid_do_safeprobe");
++ if (!libblkid.do_safeprobe)
++ return false;
++
++ libblkid.probe_lookup_value = dlsym(lib, "blkid_probe_lookup_value");
++ if (!libblkid.probe_lookup_value)
++ return false;
++
++ libblkid.free_probe = dlsym(lib, "blkid_free_probe");
++ if (!libblkid.free_probe)
++ return false;
++
++ libblkid.probe_enable_partitions = dlsym(lib, "blkid_probe_enable_partitions");
++ if (!libblkid.probe_enable_partitions)
++ return false;
++
++ libblkid.probe_set_partitions_flags = dlsym(lib, "blkid_probe_set_partitions_flags");
++ if (!libblkid.probe_set_partitions_flags)
++ return false;
++
++ libblkid.loaded = true;
++ return true;
++}
++
++static char *lookup_block_dev(const char *path, const char *key, bool is_uuid)
++{
++ int gl_flags = GLOB_NOESCAPE | GLOB_MARK;
++ const char *type, *value;
++ char *result = NULL;
++ size_t len;
++ glob_t gl;
++ int i;
++
++ if (glob(path, gl_flags, NULL, &gl) < 0)
++ return NULL;
++
++ type = is_uuid ? "PART_ENTRY_UUID" : "PART_ENTRY_NAME";
++
++ for (i = 0; i < gl.gl_pathc; i++) {
++ blkid_probe pr = libblkid.new_probe_from_filename(gl.gl_pathv[i]);
++ if (!pr)
++ continue;
++
++ libblkid.probe_enable_partitions(pr, 1);
++ libblkid.probe_set_partitions_flags(pr, BLKID_PARTS_ENTRY_DETAILS);
++
++ if (libblkid.do_safeprobe(pr))
++ goto free_pr;
++
++ if (!libblkid.probe_lookup_value(pr, type, &value, &len)) {
++ if (!strcmp(value, key))
++ result = strdup(gl.gl_pathv[i]);
++ }
++
++ free_pr:
++ libblkid.free_probe(pr);
++
++ if (result)
++ break;
++ }
++
++ globfree(&gl);
++
++ return result;
++}
++
++static char *find_block_dev(const char *key, bool is_uuid)
++{
++ char *devpath = NULL;
++ int i;
++
++ static const char *block_pats[] = {
++ "/dev/loop*",
++ "/dev/mmcblk*",
++ "/dev/sd*",
++ "/dev/hd*",
++ "/dev/md*",
++ "/dev/nvme*",
++ "/dev/vd*",
++ "/dev/xvd*",
++ "/dev/dm-*",
++ "/dev/fit*",
++ };
++
++ if (!load_libblkid())
++ return NULL;
++
++ for (i = 0; i < ARRAY_SIZE(block_pats); i++) {
++ devpath = lookup_block_dev(block_pats[i], key, is_uuid);
++ if (devpath)
++ break;
++ }
++
++ return devpath;
++}
++
++char *blockdev_parse(const char *name)
++{
++ char *e, *part_dev_path;
++ struct stat st;
++
++ if (!name)
++ return NULL;
++
++ e = strchr(name, '=');
++ if (e) {
++ *e = 0;
++ e++;
++ }
++
++ if (!e) {
++ if (stat(name, &st))
++ return NULL;
++
++ if (!S_ISBLK(st.st_mode))
++ return NULL;
++
++ part_dev_path = strdup(name);
++ } else if (!strcmp(name, "PARTLABEL")) {
++ part_dev_path = find_block_dev(e, false);
++ } else if (!strcmp(name, "PARTUUID")) {
++ if (strlen(e) != 36)
++ return NULL;
++ part_dev_path = find_block_dev(e, true);
++ } else {
++ return NULL;
++ }
++
++ return part_dev_path;
++}
++
++char *boot_param_get_dev(const char *name)
++{
++ char partkey[BOOT_PARAM_STR_MAX_LEN];
++
++ read_boot_param_string(name, partkey, sizeof(partkey));
++
++ if (!partkey[0])
++ return NULL;
++
++ return blockdev_parse(partkey);
++}
+--- a/boot_param.h
++++ b/boot_param.h
+@@ -0,0 +1,20 @@
++// SPDX-License-Identifier: BSD-3-Clause
++/*
++ * Copyright (C) 2024 MediaTek Inc. All rights reserved.
++ *
++ * Author: Weijie Gao <weijie.gao@mediatek.com>
++ */
++
++#ifndef _BOOT_PARAM_H_
++#define _BOOT_PARAM_H_
++
++#include <stddef.h>
++#include <stdbool.h>
++
++bool read_boot_param_bool(const char *name);
++int read_boot_param_string(const char *name, char *val, size_t maxsize);
++
++char *blockdev_parse(const char *name);
++char *boot_param_get_dev(const char *name);
++
++#endif /* _BOOT_PARAM_H_ */
+--- a/libfstools/rootdisk.c
++++ b/libfstools/rootdisk.c
+@@ -12,6 +12,7 @@
+ */
+
+ #include "common.h"
++#include "../boot_param.h"
+
+ #include <linux/loop.h>
+
+@@ -28,6 +29,7 @@ struct rootdev_volume {
+ struct volume v;
+ uint64_t offset;
+ char loop_name[32];
++ char *dev_path;
+ };
+
+ static const char *rootdev;
+@@ -93,6 +95,28 @@ static int get_squashfs(struct squashfs_
+ return 0;
+ }
+
++static struct volume *find_existed_rootfs_data(void)
++{
++ struct rootdev_volume *p;
++ char *rootfs_data_dev;
++
++ rootfs_data_dev = boot_param_get_dev("rootfs_data-part");
++
++ if (!rootfs_data_dev)
++ return NULL;
++
++ ULOG_NOTE("Using existed rootfs_data device %s\n", rootfs_data_dev);
++
++ p = calloc(1, sizeof(*p));
++ p->v.drv = &rootdisk_driver;
++ p->v.name = "rootfs_data";
++
++ p->offset = 0;
++ p->dev_path = rootfs_data_dev;
++
++ return &p->v;
++}
++
+ static struct volume *rootdisk_volume_find(char *name)
+ {
+ struct squashfs_super_block sb;
+@@ -101,6 +125,9 @@ static struct volume *rootdisk_volume_fi
+ if (strcmp(name, "rootfs_data") != 0)
+ return NULL;
+
++ if (read_boot_param_bool("no-split-fitrw"))
++ return find_existed_rootfs_data();
++
+ if (!rootdev)
+ rootdev = get_rootdev("/");
+ if (!rootdev)
+@@ -128,9 +155,14 @@ static struct volume *rootdisk_volume_fi
+ static int rootdisk_volume_identify(struct volume *v)
+ {
+ struct rootdev_volume *p = container_of(v, struct rootdev_volume, v);
++ const char *dev = rootdev;
+ FILE *f;
+ int ret = FS_NONE;
+- f = fopen(rootdev, "r");
++
++ if (p->dev_path)
++ dev = p->dev_path;
++
++ f = fopen(dev, "r");
+ if (!f)
+ return ret;
+
+@@ -213,6 +245,15 @@ static int rootdisk_create_loop(struct r
+ static int rootdisk_volume_init(struct volume *v)
+ {
+ struct rootdev_volume *p = container_of(v, struct rootdev_volume, v);
++ const char *dev = rootdev;
++
++ if (p->dev_path) {
++ /* Do not create loop device with no-split-fitrw set */
++ v->type = BLOCKDEV;
++ v->blk = p->dev_path;
++ dev = p->dev_path;
++ goto do_format;
++ }
+
+ if (!p->loop_name[0] && rootdisk_create_loop(p) != 0) {
+ ULOG_ERR("unable to create loop device\n");
+@@ -222,7 +263,8 @@ static int rootdisk_volume_init(struct v
+ v->type = BLOCKDEV;
+ v->blk = p->loop_name;
+
+- return block_volume_format(v, p->offset, rootdev);
++do_format:
++ return block_volume_format(v, p->offset, dev);
+ }
+
+ static struct driver rootdisk_driver = {
+--- a/libfstools/ubi.c
++++ b/libfstools/ubi.c
+@@ -12,6 +12,7 @@
+ */
+
+ #include "common.h"
++#include "../boot_param.h"
+
+ /* fit for UBI_MAX_VOLUME_NAME and sysfs path lengths */
+ #define BUFLEN 128
+@@ -140,6 +141,15 @@ static struct volume *ubi_volume_find(ch
+ DIR *ubi_dir;
+ struct dirent *ubi_dirent;
+ unsigned int ubi_num;
++ char rootfs_data_dev[127];
++
++ if (!strcmp(name, "rootfs_data")) {
++ read_boot_param_string("boot-rootfs_data-part", rootfs_data_dev,
++ sizeof(rootfs_data_dev));
++
++ if (rootfs_data_dev[0])
++ name = rootfs_data_dev;
++ }
+
+ if (find_filesystem("ubifs"))
+ return ret;
+--- a/mount_root.c
++++ b/mount_root.c
+@@ -23,6 +23,8 @@
+ #include "libfstools/libfstools.h"
+ #include "libfstools/volume.h"
+
++#include "boot_param.h"
++
+ /*
+ * Called in the early (PREINIT) stage, when we immediately need some writable
+ * filesystem.
+@@ -62,6 +64,12 @@ start(int argc, char *argv[3])
+ /* There isn't extroot, so just try to mount "rootfs_data" */
+ volume_init(data);
+ switch (volume_identify(data)) {
++ case -1:
++ /* Use ramoverlay if no "rootfs_data" device found with no-split-fitrw set */
++ if (!read_boot_param_bool("no-split-fitrw"))
++ break;
++
++ /* fall through */
+ case FS_NONE:
+ ULOG_WARN("no usable overlay filesystem found, using tmpfs overlay\n");
+ return ramoverlay();
diff --git a/master/files/target/linux/mediatek/files-6.6/arch/arm64/boot/dts/mediatek/mt7981-rfb-spim-nor.dtso b/master/files/target/linux/mediatek/files-6.6/arch/arm64/boot/dts/mediatek/mt7981-rfb-spim-nor.dtso
new file mode 100644
index 0000000..d93cbbc
--- /dev/null
+++ b/master/files/target/linux/mediatek/files-6.6/arch/arm64/boot/dts/mediatek/mt7981-rfb-spim-nor.dtso
@@ -0,0 +1,59 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (C) 2022 MediaTek Inc.
+ * Author: Sam.Shih <sam.shih@mediatek.com>
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+ compatible = "mediatek,mt7981-rfb", "mediatek,mt7981";
+
+ fragment@0 {
+ target = <&spi2>;
+ __overlay__ {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi2_flash_pins>;
+ status = "okay";
+
+ flash@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "jedec,spi-nor";
+ reg = <0>;
+ spi-max-frequency = <52000000>;
+ spi-tx-bus-width = <4>;
+ spi-rx-bus-width = <4>;
+
+ partition@00000 {
+ label = "BL2";
+ reg = <0x00000 0x0040000>;
+ };
+ partition@40000 {
+ label = "u-boot-env";
+ reg = <0x40000 0x0010000>;
+ };
+ partition@50000 {
+ label = "Factory";
+ reg = <0x50000 0x00b0000>;
+ };
+ partition@100000 {
+ label = "FIP";
+ reg = <0x100000 0x0080000>;
+ };
+ nor_rootfs: partition@180000 {
+ label = "firmware";
+ reg = <0x180000 0xe80000>;
+ };
+ };
+ };
+ };
+
+ fragment@1 {
+ target-path = "/chosen";
+ __overlay__ {
+ rootdisk-nor = <&nor_rootfs>;
+ };
+ };
+};
diff --git a/master/files/target/linux/mediatek/files-6.6/arch/arm64/boot/dts/mediatek/mt7988a-rfb-spim-nand-nmbm.dtso b/master/files/target/linux/mediatek/files-6.6/arch/arm64/boot/dts/mediatek/mt7988a-rfb-spim-nand-nmbm.dtso
new file mode 100644
index 0000000..62d4e86
--- /dev/null
+++ b/master/files/target/linux/mediatek/files-6.6/arch/arm64/boot/dts/mediatek/mt7988a-rfb-spim-nand-nmbm.dtso
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (C) 2022 MediaTek Inc.
+ * Author: Sam.Shih <sam.shih@mediatek.com>
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+ compatible = "mediatek,mt7988a-rfb", "mediatek,mt7988a";
+
+ fragment@0 {
+ target = <&spi0>;
+ __overlay__ {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi0_flash_pins>;
+ status = "okay";
+
+ flash@0 {
+ compatible = "spi-nand";
+ reg = <0>;
+ spi-max-frequency = <52000000>;
+ spi-tx-bus-width = <4>;
+ spi-rx-bus-width = <4>;
+ mediatek,nmbm;
+ mediatek,bmt-max-ratio = <1>;
+ mediatek,bmt-max-reserved-blocks = <64>;
+
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "BL2";
+ reg = <0x00000 0x0100000>;
+ read-only;
+ };
+
+ partition@100000 {
+ label = "u-boot-env";
+ reg = <0x0100000 0x0080000>;
+ };
+
+ partition@180000 {
+ label = "Factory";
+ reg = <0x180000 0x0400000>;
+ };
+
+ partition@580000 {
+ label = "FIP";
+ reg = <0x580000 0x0200000>;
+ };
+
+ partition@780000 {
+ label = "ubi";
+ reg = <0x780000 0x7080000>;
+ compatible = "linux,ubi";
+
+ volumes {
+ ubi_rootfs: ubi-volume-fit {
+ volname = "firmware";
+ };
+ };
+ };
+ };
+ };
+ };
+ };
+
+ fragment@2 {
+ target-path = "/chosen";
+ __overlay__ {
+ rootdisk-spim-nand = <&ubi_rootfs>;
+ };
+ };
+};
diff --git a/master/files/target/linux/mediatek/filogic/base-files/lib/upgrade/mtk_mmc.sh b/master/files/target/linux/mediatek/filogic/base-files/lib/upgrade/mtk_mmc.sh
new file mode 100644
index 0000000..db99960
--- /dev/null
+++ b/master/files/target/linux/mediatek/filogic/base-files/lib/upgrade/mtk_mmc.sh
@@ -0,0 +1,111 @@
+# Script for dual image A/B system boots
+# Copyright (C) 2024 MediaTek Inc.
+# Author: Weijie Gao <weijie.gao@mediatek.com>
+
+block_dev_path() {
+ local dev_path
+
+ case "$1" in
+ /dev/mmcblk*)
+ dev_path="$1"
+ ;;
+ PARTLABEL=* | PARTUUID=*)
+ dev_path=$(blkid -t "$1" -o device)
+ [ -z "${dev_path}" -o $? -ne 0 ] && return 1
+ ;;
+ *)
+ return 1;
+ ;;
+ esac
+
+ echo "${dev_path}"
+ return 0
+}
+
+mmc_dual_boot_upgrade_itb() {
+ local fit_file="$1"
+ local reserve_rootfs_data=$([ -f /sys/firmware/devicetree/base/mediatek,reserve-rootfs_data ] && echo Y)
+
+ local firmware_part=$(cat /sys/firmware/devicetree/base/mediatek,upgrade-firmware-part 2>/dev/null)
+ [ -z "${firmware_part}" -o $? -ne 0 ] && return 1
+
+ EMMC_KERN_DEV=$(block_dev_path "${firmware_part}")
+ [ -z "${EMMC_KERN_DEV}" -o $? -ne 0 ] && return 1
+
+ export EMMC_KERNEL_BLOCKS=$(($(get_image "$fit_file" | fwtool -i /dev/null -T - | dd of="$EMMC_KERN_DEV" bs=512 2>&1 | grep "records out" | cut -d' ' -f1)))
+
+ local upgrade_image_slot=$(cat /sys/firmware/devicetree/base/mediatek,upgrade-image-slot 2>/dev/null)
+ [ -n "${upgrade_image_slot}" ] && {
+ v "Set new boot image slot to ${upgrade_image_slot}"
+ # Force the creation of fw_printenv.lock
+ mkdir -p /var/lock
+ touch /var/lock/fw_printenv.lock
+ fw_setenv "dual_boot.current_slot" "${upgrade_image_slot}"
+ fw_setenv "dual_boot.slot_${upgrade_image_slot}_invalid" "0"
+ }
+
+ local rootfs_data_dev=$(cat /sys/firmware/devicetree/base/mediatek,rootfs_data-part 2>/dev/null)
+ if [ -z "${rootfs_data_dev}" -o $? -ne 0 ]; then
+ # Individual rootfs_data for each slot
+ [ -z "$UPGRADE_BACKUP" ] && dd if=/dev/zero of="$EMMC_KERN_DEV" bs=512 seek=$EMMC_KERNEL_BLOCKS count=8
+ return
+ fi
+
+ if [ x"${reserve_rootfs_data}" = xY ]; then
+ # Do not touch rootfs_data
+ return
+ fi
+
+ rootfs_data_dev=$(block_dev_path "${rootfs_data_dev}")
+ [ -z "${rootfs_data_dev}" -o $? -ne 0 ] && return 1
+
+ [ -z "$UPGRADE_BACKUP" ] && dd if=/dev/zero of="${rootfs_data_dev}" bs=512 count=8
+}
+
+mmc_do_upgrade() {
+ local file=$1
+ local dual_boot=$([ -f /sys/firmware/devicetree/base/mediatek,dual-boot ] && echo Y)
+
+ local file_type=$(identify_magic_long "$(get_magic_long "$file")")
+ case "$file_type" in
+ "fit")
+ if [ x"${dual_boot}" != xY ]; then
+ emmc_upgrade_fit "$file"
+ sync
+ return
+ fi
+
+ mmc_dual_boot_upgrade_itb "$file"
+ sync
+ ;;
+ *)
+ v "Unsupported firmware type: $file_type"
+ ;;
+ esac
+}
+
+mmc_copy_config() {
+ local dual_boot=$([ -f /sys/firmware/devicetree/base/mediatek,dual-boot ] && echo Y)
+
+ if [ x"${dual_boot}" != xY ]; then
+ emmc_copy_config
+ return
+ fi
+
+ local reserve_rootfs_data=$([ -f /sys/firmware/devicetree/base/mediatek,reserve-rootfs_data ] && echo Y)
+ if [ x"${reserve_rootfs_data}" = xY ]; then
+ # Do not touch rootfs_data
+ return
+ fi
+
+ local rootfs_data_dev=$(cat /sys/firmware/devicetree/base/mediatek,rootfs_data-part 2>/dev/null)
+ if [ -z "${rootfs_data_dev}" -o $? -ne 0 ]; then
+ emmc_copy_config
+ return
+ fi
+
+ rootfs_data_dev=$(block_dev_path "${rootfs_data_dev}")
+ [ -z "${rootfs_data_dev}" -o $? -ne 0 ] && return 1
+
+ dd if="$UPGRADE_BACKUP" of="${rootfs_data_dev}" bs=512
+}
diff --git a/master/files/target/linux/mediatek/filogic/base-files/lib/upgrade/mtk_nand.sh b/master/files/target/linux/mediatek/filogic/base-files/lib/upgrade/mtk_nand.sh
new file mode 100644
index 0000000..1b944dc
--- /dev/null
+++ b/master/files/target/linux/mediatek/filogic/base-files/lib/upgrade/mtk_nand.sh
@@ -0,0 +1,218 @@
+# Script for dual image A/B system boots
+# Copyright (C) 2024 MediaTek Inc.
+# Author: Weijie Gao <weijie.gao@mediatek.com>
+
+ubi_prepare_u_boot_env() {
+ local ubidev="$1"
+
+ local env_size=$(cat /sys/firmware/devicetree/base/mediatek,env-size 2>/dev/null)
+ [ -z "${env_size}" ] && return
+
+ local env_vol=$(cat /sys/firmware/devicetree/base/mediatek,env-ubi-volume 2>/dev/null)
+ if [ -n "${env_vol}" ]; then
+ local env_ubivol="$( nand_find_volume $ubidev $env_vol )"
+ [ -z "$env_ubivol" ] && ubimkvol /dev/$ubidev -N ${env_vol} -s ${env_size} 2>/dev/null || :
+ fi
+
+ local env2_vol=$(cat /sys/firmware/devicetree/base/mediatek,env-ubi-volume-redund 2>/dev/null)
+ if [ -n "${env2_vol}" ]; then
+ local env2_ubivol="$( nand_find_volume $ubidev $env2_vol )"
+ [ -z "$env2_ubivol" ] && ubimkvol /dev/$ubidev -N ${env2_vol} -s ${env_size} 2>/dev/null || :
+ fi
+}
+
+ubi_dual_boot_restore_config() {
+ local rootfs_data_vol=$(cat /sys/firmware/devicetree/base/mediatek,upgrade-rootfs_data-part 2>/dev/null)
+ local ubidev=$( nand_find_ubi "${CI_ROOT_UBIPART:-$CI_UBIPART}" )
+ local ubivol="$( nand_find_volume $ubidev $rootfs_data_vol )"
+ if [ ! "$ubivol" ]; then
+ ubivol="$( nand_find_volume $ubidev "$CI_ROOTPART" )"
+ if [ ! "$ubivol" ]; then
+ echo "cannot find ubifs data volume"
+ return 1
+ fi
+ fi
+ mkdir /tmp/new_root
+ if ! mount -t ubifs /dev/$ubivol /tmp/new_root; then
+ echo "cannot mount ubifs volume $ubivol"
+ rmdir /tmp/new_root
+ return 1
+ fi
+ if mv "$1" "/tmp/new_root/$BACKUP_FILE"; then
+ if umount /tmp/new_root; then
+ echo "configuration saved"
+ rmdir /tmp/new_root
+ return 0
+ fi
+ else
+ umount /tmp/new_root
+ fi
+ echo "could not save configuration to ubifs volume $ubivol"
+ rmdir /tmp/new_root
+ return 1
+}
+
+ubi_dual_boot_do_restore_config() {
+ local conf_tar="/tmp/sysupgrade.tgz"
+ [ ! -f "$conf_tar" ] || ubi_dual_boot_restore_config "$conf_tar"
+}
+
+ubi_dual_boot_do_upgrade_success() {
+ if ubi_dual_boot_do_restore_config && sync; then
+ echo "sysupgrade successful"
+ umount -a
+ reboot -f
+ fi
+ nand_do_upgrade_failed
+}
+
+dual_boot_upgrade_prepare_ubi() {
+ local boot_firmware_vol_name="$1"
+ local firmware_vol_name="$2"
+ local firmware_length="$3"
+ local reserve_rootfs_data="$4"
+
+ local ubidev="$( nand_attach_ubi "$CI_UBIPART" 0 )"
+
+ local boot_fw_ubivol="$( nand_find_volume $ubidev $boot_firmware_vol_name )"
+ local fw_ubivol="$( nand_find_volume $ubidev $firmware_vol_name )"
+ local data_ubivol="$( nand_find_volume $ubidev rootfs_data )"
+
+ # remove ubiblocks
+ [ "$boot_fw_ubivol" ] && { nand_remove_ubiblock $boot_fw_ubivol || return 1; }
+ [ "$fw_ubivol" ] && { nand_remove_ubiblock $fw_ubivol || return 1; }
+ [ "$data_ubivol" ] && { nand_remove_ubiblock $data_ubivol || return 1; }
+
+ # kill firmware volume
+ [ "$fw_ubivol" ] && ubirmvol /dev/$ubidev -N "$firmware_vol_name" || :
+
+ local rootfs_data_vol=$(cat /sys/firmware/devicetree/base/mediatek,upgrade-rootfs_data-part 2>/dev/null)
+ if [ x"${reserve_rootfs_data}" != xY ]; then
+ # kill rootfs_data volume
+ [ "$data_ubivol" ] && ubirmvol /dev/$ubidev -N "$rootfs_data_vol" || :
+ fi
+
+ # create firmware vol
+ if ! ubimkvol /dev/$ubidev -N "$firmware_vol_name" -s "$firmware_length"; then
+ echo "cannot create firmware volume"
+ return 1;
+ fi
+
+ # create u-boot environment volume
+ ubi_prepare_u_boot_env $ubidev
+
+ if [ x"${reserve_rootfs_data}" = xY ]; then
+ # Do not touch rootfs_data
+ sync
+ return 0
+ fi
+
+ # create rootfs_data vol
+ local rootfs_data_size=$(cat /sys/firmware/devicetree/base/mediatek,rootfs_data-size-limit 2>/dev/null)
+
+ if [ -n "${rootfs_data_size}" ]; then
+ rootfs_data_length="-s $rootfs_data_size"
+ else
+ rootfs_data_length="-m"
+ fi
+
+ if ! ubimkvol /dev/$ubidev -N "$rootfs_data_vol" "$rootfs_data_length"; then
+ if [ -n "${rootfs_data_size}" ]; then
+ if ! ubimkvol /dev/$root_ubidev -N "$rootfs_data_vol" -m; then
+ echo "cannot initialize $rootfs_data_vol volume"
+ return 1
+ fi
+ else
+ echo "cannot initialize $rootfs_data_vol volume"
+ return 1
+ fi
+ fi
+
+ sync
+ return 0
+}
+
+ubi_dual_boot_upgrade_itb() {
+ local fit_file="$1"
+ local gz="$2"
+
+ local boot_firmware_vol_name=$(cat /sys/firmware/devicetree/base/mediatek,boot-firmware-part 2>/dev/null)
+ [ -z "${boot_firmware_vol_name}" -o $? -ne 0 ] && return 1
+
+ local firmware_vol_name=$(cat /sys/firmware/devicetree/base/mediatek,upgrade-firmware-part 2>/dev/null)
+ [ -z "${firmware_vol_name}" -o $? -ne 0 ] && return 1
+
+ local fit_length=$( (${gz}cat "$fit_file" | wc -c) 2> /dev/null)
+
+ local reserve_rootfs_data=$([ -f /sys/firmware/devicetree/base/mediatek,reserve-rootfs_data ] && echo Y)
+ dual_boot_upgrade_prepare_ubi "${boot_firmware_vol_name}" "${firmware_vol_name}" "${fit_length}" "${reserve_rootfs_data}" || return 1
+
+ local fit_ubidev="$(nand_find_ubi "$CI_UBIPART")"
+ local fit_ubivol="$(nand_find_volume $fit_ubidev "${firmware_vol_name}")"
+
+ ${gz}cat "$fit_file" | ubiupdatevol /dev/$fit_ubivol -s "$fit_length" - || return 1
+
+ local upgrade_image_slot=$(cat /sys/firmware/devicetree/base/mediatek,upgrade-image-slot 2>/dev/null)
+ if [ -n "${upgrade_image_slot}" ]; then
+ v "Set new boot image slot to ${upgrade_image_slot}"
+ # Force the creation of fw_printenv.lock
+ mkdir -p /var/lock
+ touch /var/lock/fw_printenv.lock
+ fw_setenv "dual_boot.current_slot" "${upgrade_image_slot}"
+ fw_setenv "dual_boot.slot_${upgrade_image_slot}_invalid" "0"
+ fi
+
+ if [ x"${reserve_rootfs_data}" != xY ]; then
+ # do normal upgrade flow
+ ubi_dual_boot_do_upgrade_success
+ fi
+
+ # Do not touch rootfs_data
+ sync
+
+ echo "sysupgrade successful"
+ umount -a
+ reboot -f
+}
+
+# Write the FIT image to UBI kernel volume
+nand_upgrade_itb() {
+ local fit_file="$1"
+ local gz="$2"
+
+ local fit_length=$( (${gz}cat "$fit_file" | wc -c) 2> /dev/null)
+
+ nand_upgrade_prepare_ubi "" "" "$fit_length" "" || return 1
+
+ local fit_ubidev="$(nand_find_ubi "$CI_UBIPART")"
+ local fit_ubivol="$(nand_find_volume $fit_ubidev "$CI_KERNPART")"
+ ${gz}cat "$fit_file" | ubiupdatevol /dev/$fit_ubivol -s "$fit_length" -
+
+ # create u-boot environment volume
+ ubi_prepare_u_boot_env $fit_ubidev
+}
+
+ubi_do_upgrade() {
+ local file=$1
+ local dual_boot=$([ -f /sys/firmware/devicetree/base/mediatek,dual-boot ] && echo Y)
+
+ local gz="$(identify_if_gzip "$file")"
+ local file_type="$(identify "$file" "" "$gz")"
+
+ case "$file_type" in
+ "fit")
+ sync
+ nand_verify_if_gzip_file "$file" "$gz" || return 1
+
+ if [ x"${dual_boot}" != xY ]; then
+ nand_upgrade_itb "$file" "$gz" && nand_do_upgrade_success
+ nand_do_upgrade_failed
+ else
+ ubi_dual_boot_upgrade_itb "$file" "$gz"
+ fi
+ ;;
+ *)
+ v "Unsupported firmware type: $file_type"
+ ;;
+ esac
+}
diff --git a/master/files/target/linux/mediatek/patches-6.6/999-dual-boot-01-do-not-auto-mount-ubi-rootfs.patch b/master/files/target/linux/mediatek/patches-6.6/999-dual-boot-01-do-not-auto-mount-ubi-rootfs.patch
new file mode 100644
index 0000000..3af2c5c
--- /dev/null
+++ b/master/files/target/linux/mediatek/patches-6.6/999-dual-boot-01-do-not-auto-mount-ubi-rootfs.patch
@@ -0,0 +1,33 @@
+From: Weijie Gao <weijie.gao@mediatek.com>
+Subject: [PATCH] init: do not mount ubi rootfs if dual boot is enabled
+
+Do not mount ubi rootfs if dual boot is enabled.
+UBIFS-type rootfs volume will be specified by U-Boot.
+
+--- a/init/do_mounts.c
++++ b/init/do_mounts.c
+@@ -19,6 +19,7 @@
+ #include <linux/ramfs.h>
+ #include <linux/shmem_fs.h>
+ #include <linux/ktime.h>
++#include <linux/of.h>
+
+ #include <linux/nfs_fs.h>
+ #include <linux/nfs_fs_sb.h>
+@@ -252,9 +253,16 @@ out:
+ #ifdef CONFIG_MTD_ROOTFS_ROOT_DEV
+ static int __init mount_ubi_rootfs(void)
+ {
++ struct device_node *np;
+ int flags = MS_SILENT;
+ int err, tried = 0;
+
++ np = of_find_node_by_path("/");
++ if (np) {
++ if (of_property_read_bool(np, "mediatek,dual-boot"))
++ return -EINVAL;
++ }
++
+ while (tried < 2) {
+ err = do_mount_root("ubi0:rootfs", "ubifs", flags, \
+ root_mount_data);
diff --git a/master/files/target/linux/mediatek/patches-6.6/999-dual-boot-02-ubi-allow-no-default-rootdev.patch b/master/files/target/linux/mediatek/patches-6.6/999-dual-boot-02-ubi-allow-no-default-rootdev.patch
new file mode 100644
index 0000000..8c2522b
--- /dev/null
+++ b/master/files/target/linux/mediatek/patches-6.6/999-dual-boot-02-ubi-allow-no-default-rootdev.patch
@@ -0,0 +1,25 @@
+From: Weijie Gao <weijie.gao@mediatek.com>
+Subject: [PATCH] mtd: ubi: allow bypassing setting default rootdev
+
+Add control to bypass setting rootdev to ubi volume
+
+--- a/drivers/mtd/ubi/block.c
++++ b/drivers/mtd/ubi/block.c
+@@ -94,6 +94,9 @@ static DEFINE_IDR(ubiblock_minor_idr);
+ static DEFINE_MUTEX(devices_mutex);
+ static int ubiblock_major;
+
++static bool no_default_rootdev;
++module_param(no_default_rootdev, bool, 0444);
++
+ static int __init ubiblock_set_param(const char *val,
+ const struct kernel_param *kp)
+ {
+@@ -435,6 +438,7 @@ int ubiblock_create(struct ubi_volume_in
+
+ if (!strcmp(vi->name, "rootfs") &&
+ IS_ENABLED(CONFIG_MTD_ROOTFS_ROOT_DEV) &&
++ !no_default_rootdev &&
+ ROOT_DEV == 0) {
+ pr_notice("ubiblock: device ubiblock%d_%d (%s) set to be root filesystem\n",
+ dev->ubi_num, dev->vol_id, vi->name);
diff --git a/master/files/target/linux/mediatek/patches-6.6/999-dual-boot-03-fitblk-do-not-split-rootfs_data-if-required.patch b/master/files/target/linux/mediatek/patches-6.6/999-dual-boot-03-fitblk-do-not-split-rootfs_data-if-required.patch
new file mode 100644
index 0000000..9a4ca14
--- /dev/null
+++ b/master/files/target/linux/mediatek/patches-6.6/999-dual-boot-03-fitblk-do-not-split-rootfs_data-if-required.patch
@@ -0,0 +1,20 @@
+From: Weijie Gao <weijie.gao@mediatek.com>
+Subject: [PATCH] block: fitblk: allow bypassing creation of fitrw
+
+Add control to bypass creating fitrw
+
+--- a/drivers/block/fitblk.c
++++ b/drivers/block/fitblk.c
+@@ -579,6 +579,12 @@ static int parse_fit_on_dev(struct devic
+ slot, (slot > 1)?"s":"", (slot > 1)?"[0...":"", slot - 1,
+ (slot > 1)?"]":"");
+
++ np = of_find_node_by_path("/");
++ if (np) {
++ if (of_property_read_bool(np, "mediatek,no-split-fitrw"))
++ goto out_bootconf;
++ }
++
+ /* in case uImage.FIT is stored in a partition, map the remaining space */
+ if (!bdev->bd_read_only && bdev_is_partition(bdev) &&
+ (imgmaxsect + MIN_FREE_SECT) < dsectors) {
diff --git a/master/patches-base/0002-kernel-mtdsplit_fit-fix-rootfs_data-part-offset.patch b/master/patches-base/0002-kernel-mtdsplit_fit-fix-rootfs_data-part-offset.patch
new file mode 100644
index 0000000..56c156f
--- /dev/null
+++ b/master/patches-base/0002-kernel-mtdsplit_fit-fix-rootfs_data-part-offset.patch
@@ -0,0 +1,20 @@
+From: Weijie Gao <weijie.gao@mediatek.com>
+Subject: [PATCH] kernel: mtdsplit_fit: fix rootfs_data part offset
+
+Remove an extra erase block size to make sure keep settings work suring
+sysupgrade. Otherwise backup settings during next booting will be missing
+or corrupted.
+
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+
+--- a/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_fit.c
++++ b/target/linux/generic/files/drivers/mtd/mtdsplit/mtdsplit_fit.c
+@@ -327,7 +327,7 @@ mtdsplit_fit_parse(struct mtd_info *mtd,
+ return -ENOMEM;
+
+ parts[0].name = ROOTFS_SPLIT_NAME;
+- parts[0].offset = fit_offset + mtd_rounddown_to_eb(max_size, mtd) + mtd->erasesize;
++ parts[0].offset = fit_offset + mtd_rounddown_to_eb(max_size, mtd);
+ parts[0].size = mtd->size - parts[0].offset;
+
+ *pparts = parts;
diff --git a/master/patches-base/0050-dual-boot-fstools-add-support-to-build-libfstools-bootparam-li.patch b/master/patches-base/0050-dual-boot-fstools-add-support-to-build-libfstools-bootparam-li.patch
new file mode 100644
index 0000000..808d168
--- /dev/null
+++ b/master/patches-base/0050-dual-boot-fstools-add-support-to-build-libfstools-bootparam-li.patch
@@ -0,0 +1,63 @@
+From: Weijie Gao <weijie.gao@mediatek.com>
+Subject: [PATCH] fstools: add support to build libfstools-bootparam
+ library
+
+The libfstools-bootparam is used for dual-image support.
+
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+
+--- a/package/system/fstools/Makefile
++++ b/package/system/fstools/Makefile
+@@ -31,14 +31,21 @@ PKG_MAINTAINER:=John Crispin <john@phrozen.org>
+ include $(INCLUDE_DIR)/package.mk
+ include $(INCLUDE_DIR)/cmake.mk
+
++#TARGET_LDFLAGS += $(if $(CONFIG_USE_GLIBC),-ldl)
+ CMAKE_OPTIONS += $(if $(CONFIG_FSTOOLS_UBIFS_EXTROOT),-DCMAKE_UBIFS_EXTROOT=y)
+ CMAKE_OPTIONS += $(if $(CONFIG_FSTOOLS_OVL_MOUNT_FULL_ACCESS_TIME),-DCMAKE_OVL_MOUNT_FULL_ACCESS_TIME=y)
+ CMAKE_OPTIONS += $(if $(CONFIG_FSTOOLS_OVL_MOUNT_COMPRESS_ZLIB),-DCMAKE_OVL_MOUNT_COMPRESS_ZLIB=y)
+
++define Package/libfstools-bootparam
++ SECTION:=libs
++ CATEGORY:=Libraries
++ TITLE:=Boot parameter library for OpenWrt filesystem tools
++endef
++
+ define Package/fstools
+ SECTION:=base
+ CATEGORY:=Base system
+- DEPENDS:=+ubox +NAND_SUPPORT:ubi-utils
++ DEPENDS:=+ubox +NAND_SUPPORT:ubi-utils +libfstools-bootparam
+ TITLE:=OpenWrt filesystem tools
+ MENU:=1
+ endef
+@@ -82,7 +89,7 @@ define Package/block-mount
+ SECTION:=base
+ CATEGORY:=Base system
+ TITLE:=Block device mounting and checking
+- DEPENDS:=+ubox +libubox +libuci +libblobmsg-json +libjson-c
++ DEPENDS:=+ubox +libubox +libuci +libblobmsg-json +libjson-c +libfstools-bootparam
+ endef
+
+ define Package/blockd
+@@ -92,6 +99,12 @@ define Package/blockd
+ DEPENDS:=+block-mount +fstools +libubus +kmod-fs-autofs4 +libblobmsg-json +libjson-c
+ endef
+
++define Package/libfstools-bootparam/install
++ $(INSTALL_DIR) $(1)/lib
++
++ $(INSTALL_DATA) $(PKG_INSTALL_DIR)/usr/lib/libfstools-bootparam.so $(1)/lib/
++endef
++
+ define Package/fstools/install
+ $(INSTALL_DIR) $(1)/sbin $(1)/lib
+
+@@ -135,6 +148,7 @@ define Build/InstallDev
+ $(CP) $(PKG_INSTALL_DIR)/usr/lib/libubi-utils.a $(1)/usr/lib/
+ endef
+
++$(eval $(call BuildPackage,libfstools-bootparam))
+ $(eval $(call BuildPackage,fstools))
+ $(eval $(call BuildPackage,snapshot-tool))
+ $(eval $(call BuildPackage,block-mount))
diff --git a/master/patches-base/0100-filogic-01-add-support-for-MediaTek-RFBs.patch b/master/patches-base/0100-filogic-01-add-support-for-MediaTek-RFBs.patch
new file mode 100644
index 0000000..7386fcb
--- /dev/null
+++ b/master/patches-base/0100-filogic-01-add-support-for-MediaTek-RFBs.patch
@@ -0,0 +1,105 @@
+From: Weijie Gao <weijie.gao@mediatek.com>
+Subject: [PATCH] mediatek: filogic: add support for MediaTek RFBs
+
+Support MediaTek RFBs by using env parameters passed by u-boot via FDT.
+
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+
+--- a/package/boot/uboot-envtools/files/mediatek_filogic
++++ b/package/boot/uboot-envtools/files/mediatek_filogic
+@@ -11,6 +11,26 @@ touch /etc/config/ubootenv
+
+ board=$(board_name)
+
++block_dev_path() {
++ local dev_path
++
++ case "$1" in
++ /dev/mmcblk*)
++ dev_path="$1"
++ ;;
++ PARTLABEL=* | PARTUUID=*)
++ dev_path=$(blkid -t "$1" -o device)
++ [ -z "${dev_path}" -o $? -ne 0 ] && return 1
++ ;;
++ *)
++ return 1;
++ ;;
++ esac
++
++ echo "${dev_path}"
++ return 0
++}
++
+ ubootenv_add_mmc_default() {
+ local envdev="$(find_mmc_part "ubootenv" "${1:-mmcblk0}")"
+ ubootenv_add_uci_config "$envdev" "0x0" "0x40000" "0x40000" "1"
+@@ -33,6 +53,68 @@ ubootenv_add_ubi_default() {
+ }
+
+ case "$board" in
++mediatek,mt7981-rfb|\
++mediatek,mt7986a-rfb|\
++mediatek,mt7986b-rfb|\
++mediatek,mt7988a-rfb)
++ . /lib/upgrade/common.sh
++
++ bootdev="$(fitblk_get_bootdev)"
++ case "$bootdev" in
++ ubi*)
++ local env_ubi_vol=$(cat /sys/firmware/devicetree/base/mediatek,env-ubi-volume 2>/dev/null)
++ local env_ubi_vol2=$(cat /sys/firmware/devicetree/base/mediatek,env-ubi-volume-redund 2>/dev/null)
++ local env_size=$(cat /sys/firmware/devicetree/base/mediatek,env-size 2>/dev/null)
++
++ if [ x"${env_ubi_vol}" = x"ubootenv" -a x"${env_ubi_vol2}" = x"ubootenv2" ]; then
++ ubootenv_add_ubi_default
++ return
++ fi
++
++ . /lib/upgrade/nand.sh
++ local envubi=$(nand_find_ubi ubi)
++
++ if [ -n "${env_ubi_vol}" ]; then
++ local envdev=/dev/$(nand_find_volume $envubi "${env_ubi_vol}")
++ ubootenv_add_uci_config "$envdev" "0x0" "${env_size}" "${env_size}" "1"
++ fi
++
++ if [ -n "${env_ubi_vol2}" ]; then
++ local envdev2=/dev/$(nand_find_volume $envubi "${env_ubi_vol2}")
++ ubootenv_add_uci_config "$envdev2" "0x0" "${env_size}" "${env_size}" "1"
++ fi
++ ;;
++ mmc*)
++ local env_part=$(cat /sys/firmware/devicetree/base/mediatek,env-part 2>/dev/null)
++ local env_size=$(cat /sys/firmware/devicetree/base/mediatek,env-size 2>/dev/null)
++ local env_off=$(cat /sys/firmware/devicetree/base/mediatek,env-offset 2>/dev/null)
++ local env_redund_off=$(cat /sys/firmware/devicetree/base/mediatek,env-redund-offset 2>/dev/null)
++
++ if [ -n "${env_part}" -a -n "${env_size}" -a -n "${env_off}" ]; then
++ env_dev=$(block_dev_path "${env_part}")
++
++ ubootenv_add_uci_config "${env_dev}" "${env_off}" "${env_size}" "${env_size}" "1"
++
++ [ -n "${env_redund_off}" ] && \
++ ubootenv_add_uci_config "${env_dev}" "${env_redund_off}" "${env_size}" "${env_size}" "1"
++ fi
++ ;;
++ mtd*)
++ local env_part=$(cat /sys/firmware/devicetree/base/mediatek,env-part 2>/dev/null)
++ local env_size=$(cat /sys/firmware/devicetree/base/mediatek,env-size 2>/dev/null)
++ local env_redund_off=$(cat /sys/firmware/devicetree/base/mediatek,env-redund-offset 2>/dev/null)
++
++ if [ -n "${env_part}" -a -n "${env_size}" ]; then
++ local env_dev="/dev/mtd$(find_mtd_index "${env_part}")"
++
++ ubootenv_add_uci_config "${env_dev}" "0x0" "${env_size}" "${env_size}" "1"
++
++ [ -n "${env_redund_off}" ] && \
++ ubootenv_add_uci_config "${env_dev}" "${env_redund_off}" "${env_size}" "${env_size}" "1"
++ fi
++ ;;
++ esac
++ ;;
+ asus,rt-ax59u)
+ ubootenv_add_uci_config "/dev/mtd0" "0x100000" "0x20000" "0x20000"
+ ;;
diff --git a/master/patches-base/0100-filogic-02-add-support-for-MediaTek-RBFs-upgrade.patch b/master/patches-base/0100-filogic-02-add-support-for-MediaTek-RBFs-upgrade.patch
new file mode 100644
index 0000000..e738b2b
--- /dev/null
+++ b/master/patches-base/0100-filogic-02-add-support-for-MediaTek-RBFs-upgrade.patch
@@ -0,0 +1,80 @@
+From: Weijie Gao <weijie.gao@mediatek.com>
+Subject: [PATCH 4/8] mediatek: filogic: add support for MediaTek RBFs upgrade
+
+Add support for MediaTek RBFs upgrade (both normal and dual-image)
+
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+
+--- a/target/linux/mediatek/filogic/base-files/lib/upgrade/platform.sh
++++ b/target/linux/mediatek/filogic/base-files/lib/upgrade/platform.sh
+@@ -1,5 +1,5 @@
+ REQUIRE_IMAGE_METADATA=1
+-RAMFS_COPY_BIN='fitblk'
++RAMFS_COPY_BIN='fitblk blkid'
+
+ asus_initial_setup()
+ {
+@@ -64,6 +64,31 @@ platform_do_upgrade() {
+ local board=$(board_name)
+
+ case "$board" in
++ mediatek,mt7981-rfb|\
++ mediatek,mt7988a-rfb)
++ [ -e /dev/fit0 ] && fitblk /dev/fit0
++ [ -e /dev/fitrw ] && fitblk /dev/fitrw
++ bootdev="$(fitblk_get_bootdev)"
++ case "$bootdev" in
++ mmcblk*)
++ EMMC_KERN_DEV="/dev/$bootdev"
++ mmc_do_upgrade "$1"
++ ;;
++ mtdblock*)
++ PART_NAME="/dev/mtd${bootdev:8}"
++ default_do_upgrade "$1"
++ ;;
++ ubiblock*)
++ CI_KERNPART="firmware"
++ ubi_do_upgrade "$1"
++ ;;
++ *)
++ if grep \"rootfs_data\" /proc/mtd; then
++ default_do_upgrade "$1"
++ fi
++ ;;
++ esac
++ ;;
+ acer,predator-w6|\
+ smartrg,sdg-8612|\
+ smartrg,sdg-8614|\
+@@ -134,7 +159,6 @@ platform_do_upgrade() {
+ ;;
+ h3c,magic-nx30-pro|\
+ jcg,q30-pro|\
+- mediatek,mt7981-rfb|\
+ netcore,n60|\
+ qihoo,360t7|\
+ xiaomi,mi-router-ax3000t-ubootmod|\
+@@ -205,6 +229,8 @@ platform_check_image() {
+ [ "$#" -gt 1 ] && return 1
+
+ case "$board" in
++ mediatek,mt7981-rfb|\
++ mediatek,mt7988a-rfb|\
+ bananapi,bpi-r3|\
+ bananapi,bpi-r4|\
+ bananapi,bpi-r4-poe|\
+@@ -226,6 +252,14 @@ platform_check_image() {
+
+ platform_copy_config() {
+ case "$(board_name)" in
++ mediatek,mt7981-rfb|\
++ mediatek,mt7988a-rfb)
++ case "$(fitblk_get_bootdev)" in
++ mmcblk*)
++ mmc_copy_config
++ ;;
++ esac
++ ;;
+ cmcc,rax3000m)
+ case "$(cmdline_get_var root)" in
+ /dev/mmc*)
diff --git a/master/patches-base/0100-filogic-03-add-fitblk-support-for-MediaTek-RFB.patch b/master/patches-base/0100-filogic-03-add-fitblk-support-for-MediaTek-RFB.patch
new file mode 100644
index 0000000..3955601
--- /dev/null
+++ b/master/patches-base/0100-filogic-03-add-fitblk-support-for-MediaTek-RFB.patch
@@ -0,0 +1,128 @@
+From: Weijie Gao <weijie.gao@mediatek.com>
+Subject: [PATCH] mediatek/filogic: add fitblk support for MediaTek RFBs
+
+Add fitblk support for MediaTek RFBs
+
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+
+--- a/target/linux/mediatek/files-6.6/arch/arm64/boot/dts/mediatek/mt7981-rfb.dts
++++ b/target/linux/mediatek/files-6.6/arch/arm64/boot/dts/mediatek/mt7981-rfb.dts
+@@ -113,6 +113,22 @@
+ };
+ };
+
++ spi2_flash_pins: spi2-pins {
++ mux {
++ function = "spi";
++ groups = "spi2", "spi2_wp_hold";
++ };
++ conf-pu {
++ pins = "SPI2_CS", "SPI2_HOLD", "SPI2_WP";
++ drive-strength = <MTK_DRIVE_8mA>;
++ bias-pull-up = <MTK_PUPD_SET_R1R0_11>;
++ };
++ conf-pd {
++ pins = "SPI2_CLK", "SPI2_MOSI", "SPI2_MISO";
++ drive-strength = <MTK_DRIVE_8mA>;
++ bias-pull-down = <MTK_PUPD_SET_R1R0_11>;
++ };
++ };
+ };
+
+ &spi0 {
+--- a/target/linux/mediatek/files-6.6/arch/arm64/boot/dts/mediatek/mt7988a-rfb-emmc.dtso
++++ b/target/linux/mediatek/files-6.6/arch/arm64/boot/dts/mediatek/mt7988a-rfb-emmc.dtso
+@@ -28,6 +28,34 @@
+ no-sd;
+ no-sdio;
+ status = "okay";
++
++ card@0 {
++ compatible = "mmc-card";
++ reg = <0>;
++
++ block {
++ compatible = "block-device";
++ partitions {
++ block-partition-env {
++ partname = "u-boot-env";
++ nvmem-layout {
++ compatible = "u-boot,env-layout";
++ };
++ };
++
++ emmc_rootfs: block-partition-production {
++ partname = "firmware";
++ };
++ };
++ };
++ };
++ };
++ };
++
++ fragment@2 {
++ target-path = "/chosen";
++ __overlay__ {
++ rootdisk-emmc = <&emmc_rootfs>;
+ };
+ };
+ };
+--- a/target/linux/mediatek/files-6.6/arch/arm64/boot/dts/mediatek/mt7988a-rfb-sd.dtso
++++ b/target/linux/mediatek/files-6.6/arch/arm64/boot/dts/mediatek/mt7988a-rfb-sd.dtso
+@@ -26,6 +26,34 @@
+ vqmmc-supply = <®_3p3v>;
+ no-mmc;
+ status = "okay";
++
++ card@0 {
++ compatible = "mmc-card";
++ reg = <0>;
++
++ block {
++ compatible = "block-device";
++ partitions {
++ block-partition-env {
++ partname = "u-boot-env";
++ nvmem-layout {
++ compatible = "u-boot,env-layout";
++ };
++ };
++
++ sd_rootfs: block-partition-production {
++ partname = "firmware";
++ };
++ };
++ };
++ };
++ };
++ };
++
++ fragment@2 {
++ target-path = "/chosen";
++ __overlay__ {
++ rootdisk-sd = <&sd_rootfs>;
+ };
+ };
+ };
+--- a/target/linux/mediatek/files-6.6/arch/arm64/boot/dts/mediatek/mt7988a-rfb.dts
++++ b/target/linux/mediatek/files-6.6/arch/arm64/boot/dts/mediatek/mt7988a-rfb.dts
+@@ -18,7 +18,8 @@
+ chosen {
+ bootargs = "console=ttyS0,115200n1 loglevel=8 \
+ earlycon=uart8250,mmio32,0x11000000 \
+- pci=pcie_bus_perf";
++ pci=pcie_bus_perf ubi.block=0,firmware root=/dev/fit0 \
++ rootwait";
+ };
+
+ memory {
+--- a/target/linux/mediatek/files-6.6/arch/arm64/boot/dts/mediatek/mt7988a.dtsi
++++ b/target/linux/mediatek/files-6.6/arch/arm64/boot/dts/mediatek/mt7988a.dtsi
+@@ -828,6 +828,7 @@
+ nvmem-cells = <&lvts_calibration>;
+ nvmem-cell-names = "lvts-calib-data-1";
+ #thermal-sensor-cells = <1>;
++ status = "disabled";
+ };
+
+ ssusb0: usb@11190000 {
diff --git a/master/patches-base/0100-filogic-04-add-necessary-packages-for-MediaTek.patch b/master/patches-base/0100-filogic-04-add-necessary-packages-for-MediaTek.patch
new file mode 100644
index 0000000..88c62c4
--- /dev/null
+++ b/master/patches-base/0100-filogic-04-add-necessary-packages-for-MediaTek.patch
@@ -0,0 +1,54 @@
+From: Weijie Gao <weijie.gao@mediatek.com>
+Subject: [PATCH] mediatek/filogic: update image configs for MediaTek RFBs
+
+Add necessary packages for MediaTek RFBs:
+blkid: used for u-boot envtool
+
+Add new dts overlays for MediaTek RFBs.
+
+Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
+
+--- a/target/linux/mediatek/image/filogic.mk
++++ b/target/linux/mediatek/image/filogic.mk
+@@ -742,13 +742,14 @@ define Device/mediatek_mt7981-rfb
+ DEVICE_MODEL := MT7981 rfb
+ DEVICE_DTS := mt7981-rfb
+ DEVICE_DTS_OVERLAY:= \
++ mt7981-rfb-spim-nor \
+ mt7981-rfb-spim-nand \
+ mt7981-rfb-mxl-2p5g-phy-eth1 \
+ mt7981-rfb-mxl-2p5g-phy-swp5
+ DEVICE_DTS_DIR := $(DTS_DIR)/
+ DEVICE_DTC_FLAGS := --pad 4096
+ DEVICE_DTS_LOADADDR := 0x43f00000
+- DEVICE_PACKAGES := kmod-mt7915e kmod-mt7981-firmware kmod-usb3 e2fsprogs f2fsck mkf2fs mt7981-wo-firmware
++ DEVICE_PACKAGES := kmod-mt7915e kmod-mt7981-firmware kmod-usb3 e2fsprogs f2fsck mkf2fs mt7981-wo-firmware blkid
+ KERNEL_LOADADDR := 0x44000000
+ KERNEL := kernel-bin | gzip
+ KERNEL_INITRAMFS := kernel-bin | lzma | \
+@@ -819,7 +820,7 @@ define Device/mediatek_mt7986b-rfb
+ DEVICE_MODEL := MTK7986 rfbb AP
+ DEVICE_DTS := mt7986b-rfb
+ DEVICE_DTS_DIR := $(DTS_DIR)/
+- DEVICE_PACKAGES := kmod-mt7915e kmod-mt7986-firmware mt7986-wo-firmware
++ DEVICE_PACKAGES := kmod-mt7915e kmod-mt7986-firmware mt7986-wo-firmware blkid
+ SUPPORTED_DEVICES := mediatek,mt7986b-rfb
+ UBINIZE_OPTS := -E 5
+ BLOCKSIZE := 128k
+@@ -842,6 +843,7 @@ define Device/mediatek_mt7988a-rfb
+ mt7988a-rfb-snfi-nand \
+ mt7988a-rfb-spim-nand \
+ mt7988a-rfb-spim-nand-factory \
++ mt7988a-rfb-spim-nand-nmbm \
+ mt7988a-rfb-spim-nor \
+ mt7988a-rfb-eth1-aqr \
+ mt7988a-rfb-eth1-i2p5g-phy \
+@@ -853,7 +855,7 @@ define Device/mediatek_mt7988a-rfb
+ DEVICE_DTS_DIR := $(DTS_DIR)/
+ DEVICE_DTC_FLAGS := --pad 4096
+ DEVICE_DTS_LOADADDR := 0x45f00000
+- DEVICE_PACKAGES := mt7988-2p5g-phy-firmware kmod-sfp
++ DEVICE_PACKAGES := mt7988-2p5g-phy-firmware kmod-sfp blkid
+ KERNEL_LOADADDR := 0x46000000
+ KERNEL := kernel-bin | gzip
+ KERNEL_INITRAMFS := kernel-bin | lzma | \