[rdkb][common][bsp][Refactor and sync kernel from openwrt]

[Description]
7854d26d [openwrt][mt7988][hnat][Add extensions for 3-WED/3-WDMA offload]
25a45c80 [[openwrt][mt7986][config][free pse buffer or drop the packets that forward to pse port when the pse port link down]]
32b812fc [openwrt][mt7988][arm64: dts: mt7988: add tops pce device tree node]
a867fd44 [openwrt][mt7988][tops][TOPS Alpha release]
e7e3b623 [openwrt][mt7988][pce][TOPS Alpha release]
3009511b [MT7981 SPIM NAND: backport gigadevice.c of kernel v6.4 to v5.4]
4b93c614 [MAC80211][wed][add dma mask limitation for the board w/ >= 4GB dram]
b1cbdaec [kernel][common][config][Enable full debug information for vmlinux]
d97130d4 [openwrt][common][crypto][upgrade openssl from 1.1.1t to 1.1.1v]
b9bf21c8 [kernel][gphy][Add CH395 solution to dsa, gsw]

[Release-log]

Change-Id: I9a221d6f2303a5e0dc297c4ff4479c105a11d6c6
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/999-1410-mtd-spinand-gigadevice-Support-for-modify-GD-Serial-NAND-from-v6-4-9.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/999-1410-mtd-spinand-gigadevice-Support-for-modify-GD-Serial-NAND-from-v6-4-9.patch
new file mode 100644
index 0000000..1365854
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/999-1410-mtd-spinand-gigadevice-Support-for-modify-GD-Serial-NAND-from-v6-4-9.patch
@@ -0,0 +1,420 @@
+Index: linux-5.4.246/drivers/mtd/nand/spi/gigadevice.c
+===================================================================
+--- linux-5.4.246.orig/drivers/mtd/nand/spi/gigadevice.c
++++ linux-5.4.246/drivers/mtd/nand/spi/gigadevice.c
+@@ -13,7 +13,10 @@
+ #define GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS	(1 << 4)
+ #define GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS	(3 << 4)
+ 
+-#define GD5FXGQ4UEXXG_REG_STATUS2		0xf0
++#define GD5FXGQ5XE_STATUS_ECC_1_4_BITFLIPS	(1 << 4)
++#define GD5FXGQ5XE_STATUS_ECC_4_BITFLIPS	(3 << 4)
++
++#define GD5FXGQXXEXXG_REG_STATUS2		0xf0
+ 
+ #define GD5FXGQ4UXFXXG_STATUS_ECC_MASK		(7 << 4)
+ #define GD5FXGQ4UXFXXG_STATUS_ECC_NO_BITFLIPS	(0 << 4)
+@@ -36,6 +39,22 @@ static SPINAND_OP_VARIANTS(read_cache_va
+ 		SPINAND_PAGE_READ_FROM_CACHE_OP_3A(true, 0, 1, NULL, 0),
+ 		SPINAND_PAGE_READ_FROM_CACHE_OP_3A(false, 0, 0, NULL, 0));
+ 
++static SPINAND_OP_VARIANTS(read_cache_variants_1gq5,
++		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
++		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
++		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
++		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
++		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
++		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
++
++static SPINAND_OP_VARIANTS(read_cache_variants_2gq5,
++		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 4, NULL, 0),
++		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
++		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 2, NULL, 0),
++		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
++		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
++		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
++
+ static SPINAND_OP_VARIANTS(write_cache_variants,
+ 		SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
+ 		SPINAND_PROG_LOAD(true, 0, NULL, 0));
+@@ -102,7 +121,7 @@ static int gd5fxgq4xa_ecc_get_status(str
+ 	return -EINVAL;
+ }
+ 
+-static int gd5fxgq4_variant2_ooblayout_ecc(struct mtd_info *mtd, int section,
++static int gd5fxgqx_variant2_ooblayout_ecc(struct mtd_info *mtd, int section,
+ 				       struct mtd_oob_region *region)
+ {
+ 	if (section)
+@@ -114,7 +133,7 @@ static int gd5fxgq4_variant2_ooblayout_e
+ 	return 0;
+ }
+ 
+-static int gd5fxgq4_variant2_ooblayout_free(struct mtd_info *mtd, int section,
++static int gd5fxgqx_variant2_ooblayout_free(struct mtd_info *mtd, int section,
+ 					struct mtd_oob_region *region)
+ {
+ 	if (section)
+@@ -127,16 +146,46 @@ static int gd5fxgq4_variant2_ooblayout_f
+ 	return 0;
+ }
+ 
+-static const struct mtd_ooblayout_ops gd5fxgq4_variant2_ooblayout = {
+-	.ecc = gd5fxgq4_variant2_ooblayout_ecc,
+-	.free = gd5fxgq4_variant2_ooblayout_free,
++/* Valid for Q4/Q5 and Q6 (untested) devices */
++static const struct mtd_ooblayout_ops gd5fxgqx_variant2_ooblayout = {
++	.ecc = gd5fxgqx_variant2_ooblayout_ecc,
++	.free = gd5fxgqx_variant2_ooblayout_free,
++};
++
++static int gd5fxgq4xc_ooblayout_256_ecc(struct mtd_info *mtd, int section,
++					struct mtd_oob_region *oobregion)
++{
++	if (section)
++		return -ERANGE;
++
++	oobregion->offset = 128;
++	oobregion->length = 128;
++
++	return 0;
++}
++
++static int gd5fxgq4xc_ooblayout_256_free(struct mtd_info *mtd, int section,
++					 struct mtd_oob_region *oobregion)
++{
++	if (section)
++		return -ERANGE;
++
++	oobregion->offset = 1;
++	oobregion->length = 127;
++
++	return 0;
++}
++
++static const struct mtd_ooblayout_ops gd5fxgq4xc_oob_256_ops = {
++	.ecc = gd5fxgq4xc_ooblayout_256_ecc,
++	.free = gd5fxgq4xc_ooblayout_256_free,
+ };
+ 
+ static int gd5fxgq4uexxg_ecc_get_status(struct spinand_device *spinand,
+ 					u8 status)
+ {
+ 	u8 status2;
+-	struct spi_mem_op op = SPINAND_GET_FEATURE_OP(GD5FXGQ4UEXXG_REG_STATUS2,
++	struct spi_mem_op op = SPINAND_GET_FEATURE_OP(GD5FXGQXXEXXG_REG_STATUS2,
+ 						      &status2);
+ 	int ret;
+ 
+@@ -174,6 +223,43 @@ static int gd5fxgq4uexxg_ecc_get_status(
+ 	return -EINVAL;
+ }
+ 
++static int gd5fxgq5xexxg_ecc_get_status(struct spinand_device *spinand,
++					u8 status)
++{
++	u8 status2;
++	struct spi_mem_op op = SPINAND_GET_FEATURE_OP(GD5FXGQXXEXXG_REG_STATUS2,
++						      &status2);
++	int ret;
++
++	switch (status & STATUS_ECC_MASK) {
++	case STATUS_ECC_NO_BITFLIPS:
++		return 0;
++
++	case GD5FXGQ5XE_STATUS_ECC_1_4_BITFLIPS:
++		/*
++		 * Read status2 register to determine a more fine grained
++		 * bit error status
++		 */
++		ret = spi_mem_exec_op(spinand->spimem, &op);
++		if (ret)
++			return ret;
++
++		/*
++		 * 1 ... 4 bits are flipped (and corrected)
++		 */
++		/* bits sorted this way (1...0): ECCSE1, ECCSE0 */
++		return ((status2 & STATUS_ECC_MASK) >> 4) + 1;
++
++	case STATUS_ECC_UNCOR_ERROR:
++		return -EBADMSG;
++
++	default:
++		break;
++	}
++
++	return -EINVAL;
++}
++
+ static int gd5fxgq4ufxxg_ecc_get_status(struct spinand_device *spinand,
+ 					u8 status)
+ {
+@@ -195,7 +281,8 @@ static int gd5fxgq4ufxxg_ecc_get_status(
+ }
+ 
+ static const struct spinand_info gigadevice_spinand_table[] = {
+-	SPINAND_INFO("GD5F1GQ4xA", 0xF1,
++	SPINAND_INFO("GD5F1GQ4xA",
++		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xf1),
+ 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
+ 		     NAND_ECCREQ(8, 512),
+ 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+@@ -204,7 +291,8 @@ static const struct spinand_info gigadev
+ 		     SPINAND_HAS_QE_BIT,
+ 		     SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
+ 				     gd5fxgq4xa_ecc_get_status)),
+-	SPINAND_INFO("GD5F2GQ4xA", 0xF2,
++	SPINAND_INFO("GD5F2GQ4xA",
++		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xf2),
+ 		     NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
+ 		     NAND_ECCREQ(8, 512),
+ 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+@@ -213,7 +301,8 @@ static const struct spinand_info gigadev
+ 		     SPINAND_HAS_QE_BIT,
+ 		     SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
+ 				     gd5fxgq4xa_ecc_get_status)),
+-	SPINAND_INFO("GD5F4GQ4xA", 0xF4,
++	SPINAND_INFO("GD5F4GQ4xA",
++		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xf4),
+ 		     NAND_MEMORG(1, 2048, 64, 64, 4096, 80, 1, 1, 1),
+ 		     NAND_ECCREQ(8, 512),
+ 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+@@ -222,59 +311,205 @@ static const struct spinand_info gigadev
+ 		     SPINAND_HAS_QE_BIT,
+ 		     SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
+ 				     gd5fxgq4xa_ecc_get_status)),
+-	SPINAND_INFO("GD5F1GQ4UExxG", 0xd1,
++	SPINAND_INFO("GD5F4GQ4RC",
++		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE, 0xa4, 0x68),
++		     NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
++		     NAND_ECCREQ(8, 512),
++		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_f,
++					      &write_cache_variants,
++					      &update_cache_variants),
++		     SPINAND_HAS_QE_BIT,
++		     SPINAND_ECCINFO(&gd5fxgq4xc_oob_256_ops,
++				     gd5fxgq4ufxxg_ecc_get_status)),
++	SPINAND_INFO("GD5F4GQ4UC",
++		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE, 0xb4, 0x68),
++		     NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
++		     NAND_ECCREQ(8, 512),
++		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_f,
++					      &write_cache_variants,
++					      &update_cache_variants),
++		     SPINAND_HAS_QE_BIT,
++		     SPINAND_ECCINFO(&gd5fxgq4xc_oob_256_ops,
++				     gd5fxgq4ufxxg_ecc_get_status)),
++	SPINAND_INFO("GD5F1GQ4UExxG",
++		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xd1),
++		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
++		     NAND_ECCREQ(8, 512),
++		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++					      &write_cache_variants,
++					      &update_cache_variants),
++		     SPINAND_HAS_QE_BIT,
++		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
++				     gd5fxgq4uexxg_ecc_get_status)),
++	SPINAND_INFO("GD5F1GQ4RExxG",
++		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xc1),
+ 		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
+ 		     NAND_ECCREQ(8, 512),
+ 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ 					      &write_cache_variants,
+ 					      &update_cache_variants),
+ 		     SPINAND_HAS_QE_BIT,
+-		     SPINAND_ECCINFO(&gd5fxgq4_variant2_ooblayout,
++		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
++				     gd5fxgq4uexxg_ecc_get_status)),
++	SPINAND_INFO("GD5F2GQ4UExxG",
++		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xd2),
++		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
++		     NAND_ECCREQ(8, 512),
++		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++					      &write_cache_variants,
++					      &update_cache_variants),
++		     SPINAND_HAS_QE_BIT,
++		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
+ 				     gd5fxgq4uexxg_ecc_get_status)),
+-	SPINAND_INFO("GD5F1GQ4UFxxG", 0xb148,
++	SPINAND_INFO("GD5F2GQ4RExxG",
++		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xc2),
++		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
++		     NAND_ECCREQ(8, 512),
++		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
++					      &write_cache_variants,
++					      &update_cache_variants),
++		     SPINAND_HAS_QE_BIT,
++		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
++				     gd5fxgq4uexxg_ecc_get_status)),
++	SPINAND_INFO("GD5F1GQ4UFxxG",
++		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE, 0xb1, 0x48),
+ 		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
+ 		     NAND_ECCREQ(8, 512),
+ 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_f,
+ 					      &write_cache_variants,
+ 					      &update_cache_variants),
+ 		     SPINAND_HAS_QE_BIT,
+-		     SPINAND_ECCINFO(&gd5fxgq4_variant2_ooblayout,
++		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
+ 				     gd5fxgq4ufxxg_ecc_get_status)),
++	SPINAND_INFO("GD5F1GQ5UExxG",
++		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x51),
++		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
++		     NAND_ECCREQ(4, 512),
++		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5,
++					      &write_cache_variants,
++					      &update_cache_variants),
++		     SPINAND_HAS_QE_BIT,
++		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
++				     gd5fxgq5xexxg_ecc_get_status)),
++	SPINAND_INFO("GD5F1GQ5RExxG",
++		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x41),
++		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
++		     NAND_ECCREQ(4, 512),
++		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5,
++					      &write_cache_variants,
++					      &update_cache_variants),
++		     SPINAND_HAS_QE_BIT,
++		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
++				     gd5fxgq5xexxg_ecc_get_status)),
++	SPINAND_INFO("GD5F2GQ5UExxG",
++		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x52),
++		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
++		     NAND_ECCREQ(4, 512),
++		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_2gq5,
++					      &write_cache_variants,
++					      &update_cache_variants),
++		     SPINAND_HAS_QE_BIT,
++		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
++				     gd5fxgq5xexxg_ecc_get_status)),
++	SPINAND_INFO("GD5F2GQ5RExxG",
++		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x42),
++		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
++		     NAND_ECCREQ(4, 512),
++		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_2gq5,
++					      &write_cache_variants,
++					      &update_cache_variants),
++		     SPINAND_HAS_QE_BIT,
++		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
++				     gd5fxgq5xexxg_ecc_get_status)),
++	SPINAND_INFO("GD5F4GQ6UExxG",
++		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x55),
++		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 2, 1),
++		     NAND_ECCREQ(4, 512),
++		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_2gq5,
++					      &write_cache_variants,
++					      &update_cache_variants),
++		     SPINAND_HAS_QE_BIT,
++		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
++				     gd5fxgq5xexxg_ecc_get_status)),
++	SPINAND_INFO("GD5F4GQ6RExxG",
++		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x45),
++		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 2, 1),
++		     NAND_ECCREQ(4, 512),
++		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_2gq5,
++					      &write_cache_variants,
++					      &update_cache_variants),
++		     SPINAND_HAS_QE_BIT,
++		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
++				     gd5fxgq5xexxg_ecc_get_status)),
++	SPINAND_INFO("GD5F1GM7UExxG",
++		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x91),
++		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
++		     NAND_ECCREQ(8, 512),
++		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5,
++					      &write_cache_variants,
++					      &update_cache_variants),
++		     SPINAND_HAS_QE_BIT,
++		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
++				     gd5fxgq4uexxg_ecc_get_status)),
++	SPINAND_INFO("GD5F1GM7RExxG",
++		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x81),
++		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
++		     NAND_ECCREQ(8, 512),
++		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5,
++					      &write_cache_variants,
++					      &update_cache_variants),
++		     SPINAND_HAS_QE_BIT,
++		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
++				     gd5fxgq4uexxg_ecc_get_status)),
++	SPINAND_INFO("GD5F2GM7UExxG",
++		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x92),
++		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
++		     NAND_ECCREQ(8, 512),
++		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5,
++					      &write_cache_variants,
++					      &update_cache_variants),
++		     SPINAND_HAS_QE_BIT,
++		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
++				     gd5fxgq4uexxg_ecc_get_status)),
++	SPINAND_INFO("GD5F2GM7RExxG",
++		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x82),
++		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
++		     NAND_ECCREQ(8, 512),
++		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5,
++					      &write_cache_variants,
++					      &update_cache_variants),
++		     SPINAND_HAS_QE_BIT,
++		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
++				     gd5fxgq4uexxg_ecc_get_status)),
++	SPINAND_INFO("GD5F4GM8UExxG",
++		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x95),
++		     NAND_MEMORG(1, 2048, 128, 64, 4096, 80, 1, 1, 1),
++		     NAND_ECCREQ(8, 512),
++		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5,
++					      &write_cache_variants,
++					      &update_cache_variants),
++		     SPINAND_HAS_QE_BIT,
++		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
++				     gd5fxgq4uexxg_ecc_get_status)),
++	SPINAND_INFO("GD5F4GM8RExxG",
++		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x85),
++		     NAND_MEMORG(1, 2048, 128, 64, 4096, 80, 1, 1, 1),
++		     NAND_ECCREQ(8, 512),
++		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5,
++					      &write_cache_variants,
++					      &update_cache_variants),
++		     SPINAND_HAS_QE_BIT,
++		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
++				     gd5fxgq4uexxg_ecc_get_status)),
+ };
+ 
+-static int gigadevice_spinand_detect(struct spinand_device *spinand)
+-{
+-	u8 *id = spinand->id.data;
+-	u16 did;
+-	int ret;
+-
+-	/*
+-	 * Earlier GDF5-series devices (A,E) return [0][MID][DID]
+-	 * Later (F) devices return [MID][DID1][DID2]
+-	 */
+-
+-	if (id[0] == SPINAND_MFR_GIGADEVICE)
+-		did = (id[1] << 8) + id[2];
+-	else if (id[0] == 0 && id[1] == SPINAND_MFR_GIGADEVICE)
+-		did = id[2];
+-	else
+-		return 0;
+-
+-	ret = spinand_match_and_init(spinand, gigadevice_spinand_table,
+-				     ARRAY_SIZE(gigadevice_spinand_table),
+-				     did);
+-	if (ret)
+-		return ret;
+-
+-	return 1;
+-}
+-
+ static const struct spinand_manufacturer_ops gigadevice_spinand_manuf_ops = {
+-	.detect = gigadevice_spinand_detect,
+ };
+ 
+ const struct spinand_manufacturer gigadevice_spinand_manufacturer = {
+ 	.id = SPINAND_MFR_GIGADEVICE,
+ 	.name = "GigaDevice",
++	.chips = gigadevice_spinand_table,
++	.nchips = ARRAY_SIZE(gigadevice_spinand_table),
+ 	.ops = &gigadevice_spinand_manuf_ops,
+ };
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/999-2310-v5.7-mtd-nand-spi-rework-detect-procedure-for-different-read-id-op.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/999-2310-v5.7-mtd-nand-spi-rework-detect-procedure-for-different-read-id-op.patch
index f9c3542..a8c62fa 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/999-2310-v5.7-mtd-nand-spi-rework-detect-procedure-for-different-read-id-op.patch
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/999-2310-v5.7-mtd-nand-spi-rework-detect-procedure-for-different-read-id-op.patch
@@ -6,7 +6,6 @@
 
 ---
  drivers/mtd/nand/spi/core.c       | 86 ++++++++++++++++++++++---------
- drivers/mtd/nand/spi/gigadevice.c | 45 +++++-----------
  drivers/mtd/nand/spi/macronix.c   | 30 +++--------
  drivers/mtd/nand/spi/micron.c     | 26 ++--------
  drivers/mtd/nand/spi/paragon.c    | 28 +++-------
@@ -172,102 +171,6 @@
  	if (ret) {
  		dev_err(dev, "unknown raw ID %*phN\n", SPINAND_MAX_ID_LEN,
  			spinand->id.data);
-diff --git a/drivers/mtd/nand/spi/gigadevice.c b/drivers/mtd/nand/spi/gigadevice.c
-index b13b39763..a34c5ede1 100644
---- a/drivers/mtd/nand/spi/gigadevice.c
-+++ b/drivers/mtd/nand/spi/gigadevice.c
-@@ -195,7 +195,8 @@ static int gd5fxgq4ufxxg_ecc_get_status(struct spinand_device *spinand,
- }
- 
- static const struct spinand_info gigadevice_spinand_table[] = {
--	SPINAND_INFO("GD5F1GQ4xA", 0xF1,
-+	SPINAND_INFO("GD5F1GQ4xA",
-+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xf1),
- 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
- 		     NAND_ECCREQ(8, 512),
- 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-@@ -204,7 +205,8 @@ static const struct spinand_info gigadevice_spinand_table[] = {
- 		     SPINAND_HAS_QE_BIT,
- 		     SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
- 				     gd5fxgq4xa_ecc_get_status)),
--	SPINAND_INFO("GD5F2GQ4xA", 0xF2,
-+	SPINAND_INFO("GD5F2GQ4xA",
-+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xf2),
- 		     NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
- 		     NAND_ECCREQ(8, 512),
- 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-@@ -213,7 +215,8 @@ static const struct spinand_info gigadevice_spinand_table[] = {
- 		     SPINAND_HAS_QE_BIT,
- 		     SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
- 				     gd5fxgq4xa_ecc_get_status)),
--	SPINAND_INFO("GD5F4GQ4xA", 0xF4,
-+	SPINAND_INFO("GD5F4GQ4xA",
-+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xf4),
- 		     NAND_MEMORG(1, 2048, 64, 64, 4096, 80, 1, 1, 1),
- 		     NAND_ECCREQ(8, 512),
- 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-@@ -222,7 +225,8 @@ static const struct spinand_info gigadevice_spinand_table[] = {
- 		     SPINAND_HAS_QE_BIT,
- 		     SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
- 				     gd5fxgq4xa_ecc_get_status)),
--	SPINAND_INFO("GD5F1GQ4UExxG", 0xd1,
-+	SPINAND_INFO("GD5F1GQ4UExxG",
-+	             SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xd1),
- 		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
- 		     NAND_ECCREQ(8, 512),
- 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-@@ -231,7 +235,8 @@ static const struct spinand_info gigadevice_spinand_table[] = {
- 		     SPINAND_HAS_QE_BIT,
- 		     SPINAND_ECCINFO(&gd5fxgq4_variant2_ooblayout,
- 				     gd5fxgq4uexxg_ecc_get_status)),
--	SPINAND_INFO("GD5F1GQ4UFxxG", 0xb148,
-+	SPINAND_INFO("GD5F1GQ4UFxxG",
-+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE, 0xb1, 0x48),
- 		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
- 		     NAND_ECCREQ(8, 512),
- 		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_f,
-@@ -242,39 +247,13 @@ static const struct spinand_info gigadevice_spinand_table[] = {
- 				     gd5fxgq4ufxxg_ecc_get_status)),
- };
- 
--static int gigadevice_spinand_detect(struct spinand_device *spinand)
--{
--	u8 *id = spinand->id.data;
--	u16 did;
--	int ret;
--
--	/*
--	 * Earlier GDF5-series devices (A,E) return [0][MID][DID]
--	 * Later (F) devices return [MID][DID1][DID2]
--	 */
--
--	if (id[0] == SPINAND_MFR_GIGADEVICE)
--		did = (id[1] << 8) + id[2];
--	else if (id[0] == 0 && id[1] == SPINAND_MFR_GIGADEVICE)
--		did = id[2];
--	else
--		return 0;
--
--	ret = spinand_match_and_init(spinand, gigadevice_spinand_table,
--				     ARRAY_SIZE(gigadevice_spinand_table),
--				     did);
--	if (ret)
--		return ret;
--
--	return 1;
--}
--
- static const struct spinand_manufacturer_ops gigadevice_spinand_manuf_ops = {
--	.detect = gigadevice_spinand_detect,
- };
- 
- const struct spinand_manufacturer gigadevice_spinand_manufacturer = {
- 	.id = SPINAND_MFR_GIGADEVICE,
- 	.name = "GigaDevice",
-+	.chips = gigadevice_spinand_table,
-+	.nchips = ARRAY_SIZE(gigadevice_spinand_table),
- 	.ops = &gigadevice_spinand_manuf_ops,
- };
 diff --git a/drivers/mtd/nand/spi/macronix.c b/drivers/mtd/nand/spi/macronix.c
 index 21def3f8f..0f900f3aa 100644
 --- a/drivers/mtd/nand/spi/macronix.c
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/999-2311-mtd-spinand-gigadevice-Support-GD5F1GQ5UExxG.patch b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/999-2311-mtd-spinand-gigadevice-Support-GD5F1GQ5UExxG.patch
deleted file mode 100644
index e3e81e5..0000000
--- a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/999-2311-mtd-spinand-gigadevice-Support-GD5F1GQ5UExxG.patch
+++ /dev/null
@@ -1,142 +0,0 @@
-From 2f8ed664925318dacb6a92ca6383b5589cc2f7e1 Mon Sep 17 00:00:00 2001
-From: Sam Shih <sam.shih@mediatek.com>
-Date: Fri, 2 Jun 2023 13:06:09 +0800
-Subject: [PATCH] 
- [spi-and-storage][999-2311-mtd-spinand-gigadevice-Support-GD5F1GQ5UExxG.patch]
-
----
- drivers/mtd/nand/spi/gigadevice.c | 69 +++++++++++++++++++++++++++----
- 1 file changed, 60 insertions(+), 9 deletions(-)
-
-diff --git a/drivers/mtd/nand/spi/gigadevice.c b/drivers/mtd/nand/spi/gigadevice.c
-index a34c5ede1..937a04ce6 100644
---- a/drivers/mtd/nand/spi/gigadevice.c
-+++ b/drivers/mtd/nand/spi/gigadevice.c
-@@ -13,7 +13,10 @@
- #define GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS	(1 << 4)
- #define GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS	(3 << 4)
- 
--#define GD5FXGQ4UEXXG_REG_STATUS2		0xf0
-+#define GD5FXGQ5XE_STATUS_ECC_1_4_BITFLIPS	(1 << 4)
-+#define GD5FXGQ5XE_STATUS_ECC_4_BITFLIPS	(3 << 4)
-+
-+#define GD5FXGQXXEXXG_REG_STATUS2		0xf0
- 
- #define GD5FXGQ4UXFXXG_STATUS_ECC_MASK		(7 << 4)
- #define GD5FXGQ4UXFXXG_STATUS_ECC_NO_BITFLIPS	(0 << 4)
-@@ -102,7 +105,7 @@ static int gd5fxgq4xa_ecc_get_status(struct spinand_device *spinand,
- 	return -EINVAL;
- }
- 
--static int gd5fxgq4_variant2_ooblayout_ecc(struct mtd_info *mtd, int section,
-+static int gd5fxgqx_variant2_ooblayout_ecc(struct mtd_info *mtd, int section,
- 				       struct mtd_oob_region *region)
- {
- 	if (section)
-@@ -114,7 +117,7 @@ static int gd5fxgq4_variant2_ooblayout_ecc(struct mtd_info *mtd, int section,
- 	return 0;
- }
- 
--static int gd5fxgq4_variant2_ooblayout_free(struct mtd_info *mtd, int section,
-+static int gd5fxgqx_variant2_ooblayout_free(struct mtd_info *mtd, int section,
- 					struct mtd_oob_region *region)
- {
- 	if (section)
-@@ -127,16 +130,17 @@ static int gd5fxgq4_variant2_ooblayout_free(struct mtd_info *mtd, int section,
- 	return 0;
- }
- 
--static const struct mtd_ooblayout_ops gd5fxgq4_variant2_ooblayout = {
--	.ecc = gd5fxgq4_variant2_ooblayout_ecc,
--	.free = gd5fxgq4_variant2_ooblayout_free,
-+/* Valid for Q4/Q5 and Q6 (untested) devices */
-+static const struct mtd_ooblayout_ops gd5fxgqx_variant2_ooblayout = {
-+	.ecc = gd5fxgqx_variant2_ooblayout_ecc,
-+	.free = gd5fxgqx_variant2_ooblayout_free,
- };
- 
- static int gd5fxgq4uexxg_ecc_get_status(struct spinand_device *spinand,
- 					u8 status)
- {
- 	u8 status2;
--	struct spi_mem_op op = SPINAND_GET_FEATURE_OP(GD5FXGQ4UEXXG_REG_STATUS2,
-+	struct spi_mem_op op = SPINAND_GET_FEATURE_OP(GD5FXGQXXEXXG_REG_STATUS2,
- 						      &status2);
- 	int ret;
- 
-@@ -174,6 +178,43 @@ static int gd5fxgq4uexxg_ecc_get_status(struct spinand_device *spinand,
- 	return -EINVAL;
- }
- 
-+static int gd5fxgq5xexxg_ecc_get_status(struct spinand_device *spinand,
-+					u8 status)
-+{
-+	u8 status2;
-+	struct spi_mem_op op = SPINAND_GET_FEATURE_OP(GD5FXGQXXEXXG_REG_STATUS2,
-+						      &status2);
-+	int ret;
-+
-+	switch (status & STATUS_ECC_MASK) {
-+	case STATUS_ECC_NO_BITFLIPS:
-+		return 0;
-+
-+	case GD5FXGQ5XE_STATUS_ECC_1_4_BITFLIPS:
-+		/*
-+		 * Read status2 register to determine a more fine grained
-+		 * bit error status
-+		 */
-+		ret = spi_mem_exec_op(spinand->spimem, &op);
-+		if (ret)
-+			return ret;
-+
-+		/*
-+		 * 1 ... 4 bits are flipped (and corrected)
-+		 */
-+		/* bits sorted this way (1...0): ECCSE1, ECCSE0 */
-+		return ((status2 & STATUS_ECC_MASK) >> 4) + 1;
-+
-+	case STATUS_ECC_UNCOR_ERROR:
-+		return -EBADMSG;
-+
-+	default:
-+		break;
-+	}
-+
-+	return -EINVAL;
-+}
-+
- static int gd5fxgq4ufxxg_ecc_get_status(struct spinand_device *spinand,
- 					u8 status)
- {
-@@ -233,7 +274,7 @@ static const struct spinand_info gigadevice_spinand_table[] = {
- 					      &write_cache_variants,
- 					      &update_cache_variants),
- 		     SPINAND_HAS_QE_BIT,
--		     SPINAND_ECCINFO(&gd5fxgq4_variant2_ooblayout,
-+		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
- 				     gd5fxgq4uexxg_ecc_get_status)),
- 	SPINAND_INFO("GD5F1GQ4UFxxG",
- 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE, 0xb1, 0x48),
-@@ -243,8 +284,18 @@ static const struct spinand_info gigadevice_spinand_table[] = {
- 					      &write_cache_variants,
- 					      &update_cache_variants),
- 		     SPINAND_HAS_QE_BIT,
--		     SPINAND_ECCINFO(&gd5fxgq4_variant2_ooblayout,
-+		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
- 				     gd5fxgq4ufxxg_ecc_get_status)),
-+	SPINAND_INFO("GD5F1GQ5UExxG",
-+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x51),
-+		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
-+		     NAND_ECCREQ(4, 512),
-+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-+					      &write_cache_variants,
-+					      &update_cache_variants),
-+		     SPINAND_HAS_QE_BIT,
-+		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
-+				     gd5fxgq5xexxg_ecc_get_status)),
- };
- 
- static const struct spinand_manufacturer_ops gigadevice_spinand_manuf_ops = {
--- 
-2.34.1
-
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/backport-5.4.inc b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/backport-5.4.inc
index d2c5014..10b63da 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/backport-5.4.inc
+++ b/recipes-kernel/linux/linux-mediatek-5.4/generic/backport-5.4/backport-5.4.inc
@@ -300,10 +300,10 @@
     file://900-v5.9-0001-dt-bindings-Add-multicolor-class-dt-bindings-documen.patch \
     file://900-v5.9-0002-leds-Add-multicolor-ID-to-the-color-ID-list.patch \
     file://900-v5.9-0003-leds-add-RGB-color-option-as-that-is-different-from-.patch \
+    file://999-1410-mtd-spinand-gigadevice-Support-for-modify-GD-Serial-NAND-from-v6-4-9.patch \
     file://999-1900-lib-add-Dhrystone-benchmark-test.patch \
     file://999-2210-v6.1-iio-adc-add-rtq6056-support.patch \
     file://999-2310-v5.7-mtd-nand-spi-rework-detect-procedure-for-different-read-id-op.patch \
-    file://999-2311-mtd-spinand-gigadevice-Support-GD5F1GQ5UExxG.patch \
     file://999-2312-mtd-spinand-macronix-Add-support-for-MX31LF1GE4BC.patch \
     file://999-2313-mtd-spinand-macronix-Add-support-for-MX31UF1GE4BC.patch \
     file://999-2314-mtd-spinand-macronix-Add-support-for-MX35LFxGE4AD.patch \
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988.dtsi b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988.dtsi
index 3033801..92b32c5 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988.dtsi
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/arch/arm64/boot/dts/mediatek/mt7988.dtsi
@@ -370,6 +370,61 @@
 
 	};
 
+	tops: tops@09100000 {
+		compatible = "mediatek,tops";
+		reg = <0 0x09100000 0 0x01000000>;
+		reg-names = "tops-base";
+		clocks = <&topckgen CK_TOP_BUS_TOPS_SEL>,
+			 <&topckgen CK_TOP_TOPS_P2_26M_SEL>,
+			 <&topckgen CK_TOP_NETSYS_TOPS_400M_SEL>,
+			 <&topckgen CK_TOP_NPU_TOPS_SEL>,
+			 <&topckgen CK_TOP_CK_NPU_SEL_CM_TOPS_SEL>;
+		clock-names = "bus", "sram", "xdma", "offload", "mgmt";
+		power-domains = <&topmisc MT7988_POWER_DOMAIN_TOPS0>,
+				<&topmisc MT7988_POWER_DOMAIN_TOPS1>;
+
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_SPI 196 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 280 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 281 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-names = "tdma-tx-pause", "mbox", "wdt";
+
+		dmas = <&hpdma1 0>;
+		dma-names = "tnl-sync";
+
+		fe_mem = <&eth>;
+	};
+
+	tops-mbox {
+		compatible = "mediatek,tops-mbox";
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_SPI 280 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-names = "mbox";
+		tops = <&tops>;
+	};
+
+	hpdma1: hpdma@09106000 {
+		compatible = "mediatek,hpdma-top";
+		reg = <0 0x09106000 0 0x1000>;
+		reg-names = "base";
+		#dma-cells = <1>;
+	};
+
+	hpdma2: hpdma@09606000 {
+		compatible = "mediatek,hpdma-sub";
+		reg = <0 0x09606000 0 0x1000>;
+		reg-names = "base";
+		#dma-cells = <2>;
+	};
+
+	tops-ocd@0e500000 {
+		compatible = "mediatek,tops-ocd";
+		reg = <0 0x0e500000 0 0x15000>;
+		reg-names = "tops-ocd-base";
+		clocks = <&infracfg_ao CK_INFRA_AUD_L>;
+		clock-names = "debugsys";
+	};
+
 	watchdog: watchdog@1001c000 {
 		compatible = "mediatek,mt7622-wdt",
 			     "mediatek,mt6589-wdt",
@@ -865,6 +920,12 @@
 		status = "disabled";
 	};
 
+	pce: pce@15100000 {
+		compatible = "mediatek,pce";
+
+		fe_mem = <&eth>;
+	};
+
 	sgmiisys0: syscon@10060000 {
 		compatible = "mediatek,mt7988-sgmiisys",
 			     "mediatek,mt7988-sgmiisys_0",
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index 6272f11..29630a8 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -875,6 +875,82 @@
 	return 1;
 }
 
+static int mtk_gdm_fsm_get(struct mtk_mac *mac, u32 gdm)
+{
+	u32 fsm = mtk_r32(mac->hw, gdm);
+	u32 ret = 0;
+
+	if (mac->type == MTK_GDM_TYPE)
+		ret = fsm == 0;
+	else if (mac->type == MTK_XGDM_TYPE) {
+		if (mac->id == MTK_GMAC1_ID) {
+			if (((fsm & 0x7ffffff) == 0) &&
+				(mtk_r32(mac->hw, MTK_MAC_FSM(mac->id)) == 0x1010000))
+				ret = 1;
+		} else
+			ret = ((mac->interface == PHY_INTERFACE_MODE_XGMII) ?
+				((fsm & 0xfffffff) == 0) : ((fsm & 0x0ffffff) == 0));
+	}
+
+	return ret;
+}
+
+static void mtk_gdm_fsm_poll(struct mtk_mac *mac)
+{
+	u32 gdm = 0, i = 0;
+
+	switch (mac->id) {
+	case MTK_GMAC1_ID:
+		gdm = MTK_FE_GDM1_FSM;
+		break;
+	case MTK_GMAC2_ID:
+		gdm = MTK_FE_GDM2_FSM;
+		break;
+	case MTK_GMAC3_ID:
+		gdm = MTK_FE_GDM3_FSM;
+		break;
+	default:
+		pr_info("%s mac id invalid", __func__);
+		break;
+	}
+	msleep(500);
+	while (i < 3) {
+		if (mtk_gdm_fsm_get(mac, gdm))
+			break;
+		msleep(500);
+		i++;
+	}
+
+	if (i == 3)
+		pr_info("%s fsm invalid", __func__);
+}
+
+static void mtk_pse_port_link_set(struct mtk_mac *mac, bool up)
+{
+	u32 fe_glo_cfg, val;
+
+	fe_glo_cfg = mtk_r32(mac->hw, MTK_FE_GLO_CFG(mac->id));
+	switch (mac->id) {
+	case MTK_GMAC1_ID:
+		val = MTK_FE_LINK_DOWN_P1;
+		break;
+	case MTK_GMAC2_ID:
+		val = MTK_FE_LINK_DOWN_P2;
+		break;
+	case MTK_GMAC3_ID:
+		val = MTK_FE_LINK_DOWN_P15;
+		break;
+	}
+
+	if (!up)
+		fe_glo_cfg |= val;
+	else
+		fe_glo_cfg &= ~val;
+
+	mtk_w32(mac->hw, fe_glo_cfg, MTK_FE_GLO_CFG(mac->id));
+	mtk_gdm_fsm_poll(mac);
+}
+
 static void mtk_mac_link_down(struct phylink_config *config, unsigned int mode,
 			      phy_interface_t interface)
 {
@@ -882,9 +958,10 @@
 					   phylink_config);
 	u32 mcr, sts;
 
+	mtk_pse_port_link_set(mac, false);
 	if (mac->type == MTK_GDM_TYPE) {
 		mcr = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id));
-		mcr &= ~(MAC_MCR_TX_EN | MAC_MCR_RX_EN);
+		mcr &= ~(MAC_MCR_TX_EN | MAC_MCR_RX_EN | MAC_MCR_FORCE_LINK);
 		mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id));
 	} else if (mac->type == MTK_XGDM_TYPE && mac->id != MTK_GMAC1_ID) {
 		mcr = mtk_r32(mac->hw, MTK_XMAC_MCR(mac->id));
@@ -986,6 +1063,7 @@
 		mcr &= ~(XMAC_MCR_TRX_DISABLE);
 		mtk_w32(mac->hw, mcr, MTK_XMAC_MCR(mac->id));
 	}
+	mtk_pse_port_link_set(mac, true);
 }
 
 static void mtk_validate(struct phylink_config *config,
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h
index 57bf7b1..f87635c 100755
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -69,9 +69,12 @@
 #define MTK_RSS_MAX_INDIRECTION_TABLE	128
 
 /* Frame Engine Global Configuration */
-#define MTK_FE_GLO_CFG		0x00
+#define MTK_FE_GLO_CFG(x)		((x == MTK_GMAC3_ID) ? 0x24 : 0x00)
+#define MTK_FE_LINK_DOWN_P1	BIT(9)
+#define MTK_FE_LINK_DOWN_P2	BIT(10)
 #define MTK_FE_LINK_DOWN_P3	BIT(11)
 #define MTK_FE_LINK_DOWN_P4	BIT(12)
+#define MTK_FE_LINK_DOWN_P15	BIT(7)
 
 /* Frame Engine Global Reset Register */
 #define MTK_RST_GL		0x04
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h
index 2337f0e..331fce9 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h
@@ -1048,7 +1048,8 @@
 #define FROM_GE_VIRTUAL(skb) (skb_hnat_iface(skb) == FOE_MAGIC_GE_VIRTUAL)
 #define FROM_EXT(skb) (skb_hnat_iface(skb) == FOE_MAGIC_EXT)
 #define FROM_WED(skb) ((skb_hnat_iface(skb) == FOE_MAGIC_WED0) ||		\
-		       (skb_hnat_iface(skb) == FOE_MAGIC_WED1))
+		       (skb_hnat_iface(skb) == FOE_MAGIC_WED1) ||		\
+		       (skb_hnat_iface(skb) == FOE_MAGIC_WED2))
 #define FOE_MAGIC_GE_LAN 0x1
 #define FOE_MAGIC_GE_WAN 0x2
 #define FOE_MAGIC_EXT 0x3
@@ -1084,6 +1085,7 @@
 #define NR_DISCARD 7
 #define NR_WDMA0_PORT 8
 #define NR_WDMA1_PORT 9
+#define NR_WDMA2_PORT 13
 #define NR_GMAC3_PORT 15
 #define LAN_DEV_NAME hnat_priv->lan
 #define LAN2_DEV_NAME hnat_priv->lan2
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
index 59b3e71..31c03ca 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
@@ -1834,7 +1834,7 @@
 		skb_hnat_wc_id(skb), skb_hnat_rx_id(skb));
 
 	if ((gmac_no != NR_WDMA0_PORT) && (gmac_no != NR_WDMA1_PORT) &&
-	    (gmac_no != NR_WHNAT_WDMA_PORT))
+	    (gmac_no != NR_WDMA2_PORT) && (gmac_no != NR_WHNAT_WDMA_PORT))
 		return NF_ACCEPT;
 
 	if (unlikely(!skb_mac_header_was_set(skb)))
@@ -1914,7 +1914,8 @@
 		     gmac_no == NR_WHNAT_WDMA_PORT) ||
 		    ((hnat_priv->data->version == MTK_HNAT_V2 ||
 		      hnat_priv->data->version == MTK_HNAT_V3) &&
-		     (gmac_no == NR_WDMA0_PORT || gmac_no == NR_WDMA1_PORT))) {
+		     (gmac_no == NR_WDMA0_PORT || gmac_no == NR_WDMA1_PORT ||
+		      gmac_no == NR_WDMA2_PORT))) {
 			entry->ipv4_hnapt.winfo.bssid = skb_hnat_bss_id(skb);
 			entry->ipv4_hnapt.winfo.wcid = skb_hnat_wc_id(skb);
 #if defined(CONFIG_MEDIATEK_NETSYS_V3)
@@ -1984,7 +1985,8 @@
 		     gmac_no == NR_WHNAT_WDMA_PORT) ||
 		    ((hnat_priv->data->version == MTK_HNAT_V2 ||
 		      hnat_priv->data->version == MTK_HNAT_V3) &&
-		     (gmac_no == NR_WDMA0_PORT || gmac_no == NR_WDMA1_PORT))) {
+		     (gmac_no == NR_WDMA0_PORT || gmac_no == NR_WDMA1_PORT ||
+		      gmac_no == NR_WDMA2_PORT))) {
 			entry->ipv6_5t_route.winfo.bssid = skb_hnat_bss_id(skb);
 			entry->ipv6_5t_route.winfo.wcid = skb_hnat_wc_id(skb);
 #if defined(CONFIG_MEDIATEK_NETSYS_V3)
@@ -2063,6 +2065,8 @@
 		skb_hnat_sport(skb) = NR_WDMA0_PORT;
 	else if (skb_hnat_iface(skb) == FOE_MAGIC_WED1)
 		skb_hnat_sport(skb) = NR_WDMA1_PORT;
+	else if (skb_hnat_iface(skb) == FOE_MAGIC_WED2)
+		skb_hnat_sport(skb) = NR_WDMA2_PORT;
 
 	return NF_ACCEPT;
 }
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mediatek-ge.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mediatek-ge.c
index 977a90b..60ef22c 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mediatek-ge.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mediatek-ge.c
@@ -11,6 +11,10 @@
 #define MTK_PHY_PAGE_EXTENDED_2A30	0x2a30
 #define MTK_PHY_PAGE_EXTENDED_52B5	0x52b5
 
+#define MTK_PHY_RG_DEV1E_REG2C7		0x2c7
+#define   MTK_PHY_MAX_GAIN_MASK		GENMASK(4, 0)
+#define   MTK_PHY_MIN_GAIN_MASK		GENMASK(12, 8)
+
 static int mtk_gephy_read_page(struct phy_device *phydev)
 {
 	return __phy_read(phydev, MTK_EXT_PAGE_ACCESS);
@@ -65,6 +69,11 @@
 	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x13, 0x404);
 	phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x14, 0x404);
 
+	/* Adjust RX min/max gain to fix CH395 100Mbps link up fail */
+	phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG2C7,
+		      FIELD_PREP(MTK_PHY_MAX_GAIN_MASK, 0x8) |
+		      FIELD_PREP(MTK_PHY_MIN_GAIN_MASK, 0x13));
+
 	return 0;
 }
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt7531.c b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt7531.c
index b27c679..4cfb0ef 100755
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt7531.c
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/files-5.4/drivers/net/phy/mtk/mt753x/mt7531.c
@@ -132,6 +132,10 @@
 #define PHY_DEV1E_REG_189		0x189
 #define PHY_DEV1E_REG_234		0x234
 
+#define PHY_DEV1E_REG_2C7		0x2c7
+#define   MTK_PHY_MAX_GAIN_MASK		GENMASK(4, 0)
+#define   MTK_PHY_MIN_GAIN_MASK		GENMASK(12, 8)
+
 /* Fields of PHY_DEV1E_REG_0C6 */
 #define PHY_POWER_SAVING_S		8
 #define PHY_POWER_SAVING_M		0x300
@@ -874,6 +878,11 @@
 		val = gsw->mii_read(gsw, i, MII_ADVERTISE);
 		val |= ADVERTISE_PAUSE_ASYM;
 		gsw->mii_write(gsw, i, MII_ADVERTISE, val);
+
+		/* Adjust RX min/max gain to fix CH395 100Mbps link up fail */
+		gsw->mmd_write(gsw, i, PHY_DEV1E, PHY_DEV1E_REG_2C7,
+			       FIELD_PREP(MTK_PHY_MAX_GAIN_MASK, 0x8) |
+			       FIELD_PREP(MTK_PHY_MIN_GAIN_MASK, 0x13));
 	}
 }
 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7986.cfg b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7986.cfg
index 2f3f416..830294f 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7986.cfg
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/mt7986.cfg
@@ -301,7 +301,7 @@
 CONFIG_MDIO_BUS=y
 CONFIG_MDIO_DEVICE=y
 # CONFIG_MEDIATEK_2P5GE_PHY is not set
-# CONFIG_MEDIATEK_GE_PHY is not set
+CONFIG_MEDIATEK_GE_PHY=y
 # CONFIG_MEDIATEK_GE_SOC_PHY is not set
 CONFIG_MEDIATEK_MT6577_AUXADC=y
 CONFIG_MEDIATEK_NETSYS_V2=y
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4100-mtk-tops-tunnel-offload-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4100-mtk-tops-tunnel-offload-support.patch
new file mode 100644
index 0000000..a4a6d95
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4100-mtk-tops-tunnel-offload-support.patch
@@ -0,0 +1,450 @@
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -245,6 +245,9 @@ static const char * const mtk_clks_sourc
+ 	"top_netsys_warp_sel",
+ };
+ 
++struct net_device *(*mtk_get_tnl_dev)(int tnl_idx) = NULL;
++EXPORT_SYMBOL(mtk_get_tnl_dev);
++
+ void mtk_w32(struct mtk_eth *eth, u32 val, unsigned reg)
+ {
+ 	__raw_writel(val, eth->base + reg);
+@@ -2089,6 +2092,7 @@ static int mtk_poll_rx(struct napi_struc
+ 	u64 addr64 = 0;
+ 	u8 *data, *new_data;
+ 	struct mtk_rx_dma_v2 *rxd, trxd;
++	int tnl_idx = 0;
+ 	int done = 0;
+ 
+ 	if (unlikely(!ring))
+@@ -2132,11 +2136,20 @@ static int mtk_poll_rx(struct napi_struc
+ 				      0 : RX_DMA_GET_SPORT(trxd.rxd4) - 1;
+ 		}
+ 
+-		if (unlikely(mac < 0 || mac >= MTK_MAC_COUNT ||
+-			     !eth->netdev[mac]))
+-			goto release_desc;
++		tnl_idx = RX_DMA_GET_TOPS_CRSN(trxd.rxd6);
++		if (mtk_get_tnl_dev && tnl_idx) {
++			netdev = mtk_get_tnl_dev(tnl_idx);
++			if (unlikely(IS_ERR(netdev)))
++				netdev = NULL;
++		}
+ 
+-		netdev = eth->netdev[mac];
++		if (!netdev) {
++			if (unlikely(mac < 0 || mac >= MTK_MAC_COUNT ||
++				     !eth->netdev[mac]))
++				goto release_desc;
++
++			netdev = eth->netdev[mac];
++		}
+ 
+ 		if (unlikely(test_bit(MTK_RESETTING, &eth->state)))
+ 			goto release_desc;
+@@ -2221,6 +2234,8 @@ static int mtk_poll_rx(struct napi_struc
+ 		skb_hnat_alg(skb) = 0;
+ 		skb_hnat_filled(skb) = 0;
+ 		skb_hnat_magic_tag(skb) = HNAT_MAGIC_TAG;
++		skb_hnat_set_tops(skb, 0);
++		skb_hnat_set_is_decap(skb, 0);
+ 
+ 		if (skb_hnat_reason(skb) == HIT_BIND_FORCE_TO_CPU) {
+ 			trace_printk("[%s] reason=0x%x(force to CPU) from WAN to Ext\n",
+--- a/drivers/net/ethernet/mediatek/mtk_hnat/hnat.c
++++ b/drivers/net/ethernet/mediatek/mtk_hnat/hnat.c
+@@ -43,6 +43,12 @@ void (*ppe_dev_register_hook)(struct net
+ EXPORT_SYMBOL(ppe_dev_register_hook);
+ void (*ppe_dev_unregister_hook)(struct net_device *dev) = NULL;
+ EXPORT_SYMBOL(ppe_dev_unregister_hook);
++int (*mtk_tnl_encap_offload)(struct sk_buff *skb) = NULL;
++EXPORT_SYMBOL(mtk_tnl_encap_offload);
++int (*mtk_tnl_decap_offload)(struct sk_buff *skb) = NULL;
++EXPORT_SYMBOL(mtk_tnl_decap_offload);
++bool (*mtk_tnl_decap_offloadable)(struct sk_buff *skb) = NULL;
++EXPORT_SYMBOL(mtk_tnl_decap_offloadable);
+ 
+ static void hnat_sma_build_entry(struct timer_list *t)
+ {
+@@ -53,6 +59,16 @@ static void hnat_sma_build_entry(struct
+ 			     SMA, SMA_FWD_CPU_BUILD_ENTRY);
+ }
+ 
++struct foe_entry *hnat_get_foe_entry(u32 ppe_id, u32 index)
++{
++	if (index == 0x7fff || index >= hnat_priv->foe_etry_num
++	    || ppe_id >= CFG_PPE_NUM)
++		return ERR_PTR(-EINVAL);
++
++	return &hnat_priv->foe_table_cpu[ppe_id][index];
++}
++EXPORT_SYMBOL(hnat_get_foe_entry);
++
+ void hnat_cache_ebl(int enable)
+ {
+ 	int i;
+@@ -63,6 +79,7 @@ void hnat_cache_ebl(int enable)
+ 		cr_set_field(hnat_priv->ppe_base[i] + PPE_CAH_CTRL, CAH_EN, enable);
+ 	}
+ }
++EXPORT_SYMBOL(hnat_cache_ebl);
+ 
+ static void hnat_reset_timestamp(struct timer_list *t)
+ {
+--- a/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h
++++ b/drivers/net/ethernet/mediatek/mtk_hnat/hnat.h
+@@ -1085,6 +1085,8 @@ enum FoeIpAct {
+ #define NR_WDMA0_PORT 8
+ #define NR_WDMA1_PORT 9
+ #define NR_GMAC3_PORT 15
++#define NR_TDMA_TPORT 4
++#define NR_TDMA_QDMA_TPORT 5
+ #define LAN_DEV_NAME hnat_priv->lan
+ #define LAN2_DEV_NAME hnat_priv->lan2
+ #define IS_WAN(dev)                                                            \
+@@ -1208,6 +1210,8 @@ static inline bool hnat_dsa_is_enable(st
+ }
+ #endif
+ 
++struct foe_entry *hnat_get_foe_entry(u32 ppe_id, u32 index);
++
+ void hnat_deinit_debugfs(struct mtk_hnat *h);
+ int hnat_init_debugfs(struct mtk_hnat *h);
+ int hnat_register_nf_hooks(void);
+@@ -1224,6 +1228,9 @@ extern int qos_ul_toggle;
+ extern int hook_toggle;
+ extern int mape_toggle;
+ extern int qos_toggle;
++extern int (*mtk_tnl_encap_offload)(struct sk_buff *skb);
++extern int (*mtk_tnl_decap_offload)(struct sk_buff *skb);
++extern bool (*mtk_tnl_decap_offloadable)(struct sk_buff *skb);
+ 
+ int ext_if_add(struct extdev_entry *ext_entry);
+ int ext_if_del(struct extdev_entry *ext_entry);
+--- a/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
++++ b/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
+@@ -726,10 +726,14 @@ static unsigned int is_ppe_support_type(
+ 	case ETH_P_IP:
+ 		iph = ip_hdr(skb);
+ 
+-		/* do not accelerate non tcp/udp traffic */
+-		if ((iph->protocol == IPPROTO_TCP) ||
++		if (mtk_tnl_decap_offloadable && mtk_tnl_decap_offloadable(skb)) {
++			/* tunnel protocol is offloadable */
++			skb_hnat_set_is_decap(skb, 1);
++			return 1;
++		} else if ((iph->protocol == IPPROTO_TCP) ||
+ 		    (iph->protocol == IPPROTO_UDP) ||
+ 		    (iph->protocol == IPPROTO_IPV6)) {
++			/* do not accelerate non tcp/udp traffic */
+ 			return 1;
+ 		}
+ 
+@@ -846,6 +850,13 @@ mtk_hnat_ipv4_nf_pre_routing(void *priv,
+ 
+ 	hnat_set_head_frags(state, skb, -1, hnat_set_iif);
+ 
++	if (skb_hnat_tops(skb) && skb_hnat_is_decap(skb)
++	    && is_magic_tag_valid(skb)
++	    && skb_hnat_iface(skb) == FOE_MAGIC_GE_VIRTUAL
++	    && mtk_tnl_decap_offload && mtk_tnl_decap_offload(skb)) {
++		return NF_ACCEPT;
++	}
++
+ 	/*
+ 	 * Avoid mistakenly binding of outer IP, ports in SW L2TP decap flow.
+ 	 * In pre-routing, if dev is virtual iface, TOPS module is not loaded,
+@@ -922,6 +933,13 @@ mtk_hnat_br_nf_local_in(void *priv, stru
+ 
+ 	hnat_set_head_frags(state, skb, -1, hnat_set_iif);
+ 
++	if (skb_hnat_tops(skb) && skb_hnat_is_decap(skb)
++	    && is_magic_tag_valid(skb)
++	    && skb_hnat_iface(skb) == FOE_MAGIC_GE_VIRTUAL
++	    && mtk_tnl_decap_offload && mtk_tnl_decap_offload(skb)) {
++		return NF_ACCEPT;
++	}
++
+ 	pre_routing_print(skb, state->in, state->out, __func__);
+ 
+ 	if (unlikely(debug_level >= 7)) {
+@@ -1074,9 +1092,22 @@ static unsigned int hnat_ipv4_get_nextho
+ 		return -1;
+ 	}
+ 
++	/*
++	 * if this packet is a tunnel packet and is about to construct
++	 * outer header, we must update its outer mac header pointer
++	 * before filling outer mac or it may screw up inner mac
++	 */
++	if (skb_hnat_tops(skb) && skb_hnat_is_encap(skb)) {
++		skb_push(skb, sizeof(struct ethhdr));
++		skb_reset_mac_header(skb);
++	}
++
+ 	memcpy(eth_hdr(skb)->h_dest, neigh->ha, ETH_ALEN);
+ 	memcpy(eth_hdr(skb)->h_source, out->dev_addr, ETH_ALEN);
+ 
++	if (skb_hnat_tops(skb) && skb_hnat_is_encap(skb))
++		skb_pull(skb, sizeof(struct ethhdr));
++
+ 	rcu_read_unlock_bh();
+ 
+ 	return 0;
+@@ -1202,6 +1233,37 @@ static struct ethhdr *get_ipv6_ipip_ethh
+ 	return eth;
+ }
+ 
++static inline void hnat_get_filled_unbind_entry(struct sk_buff *skb,
++						struct foe_entry *entry)
++{
++	if (unlikely(!skb || !entry))
++		return;
++
++	memcpy(entry,
++	       &hnat_priv->foe_table_cpu[skb_hnat_ppe(skb)][skb_hnat_entry(skb)],
++	       sizeof(*entry));
++}
++
++static inline void hnat_fill_offload_engine_entry(struct sk_buff *skb,
++						  struct foe_entry *entry)
++{
++#if defined(CONFIG_MEDIATEK_NETSYS_V3)
++	if (skb_hnat_tops(skb) && skb_hnat_is_encap(skb)) {
++		/*
++		 * if skb_hnat_tops(skb) is setup for encapsulation,
++		 * we fill in hnat tport and tops_entry for tunnel encapsulation
++		 * offloading
++		 */
++		entry->ipv4_hnapt.tport_id = NR_TDMA_QDMA_TPORT;
++		entry->ipv4_hnapt.tops_entry = skb_hnat_tops(skb);
++	} else {
++		return;
++	}
++
++	entry->ipv4_hnapt.iblk2.qid = 12; /* offload engine use QID 12 */
++#endif /* defined(CONFIG_MEDIATEK_NETSYS_V3) */
++}
++
+ static unsigned int skb_to_hnat_info(struct sk_buff *skb,
+ 				     const struct net_device *dev,
+ 				     struct foe_entry *foe,
+@@ -1237,6 +1299,11 @@ static unsigned int skb_to_hnat_info(str
+ 	if (whnat && is_hnat_pre_filled(foe))
+ 		return 0;
+ 
++	if (skb_hnat_tops(skb) && !(hw_path->flags & FLOW_OFFLOAD_PATH_TNL)) {
++		hnat_get_filled_unbind_entry(skb, &entry);
++		goto hnat_entry_bind;
++	}
++
+ 	entry.bfib1.pkt_type = foe->udib1.pkt_type; /* Get packte type state*/
+ 	entry.bfib1.state = foe->udib1.state;
+ 
+@@ -1247,6 +1314,7 @@ static unsigned int skb_to_hnat_info(str
+ 	switch (ntohs(eth->h_proto)) {
+ 	case ETH_P_IP:
+ 		iph = ip_hdr(skb);
++
+ 		switch (iph->protocol) {
+ 		case IPPROTO_UDP:
+ 			udp = 1;
+@@ -1628,6 +1696,10 @@ static unsigned int skb_to_hnat_info(str
+ 	/* Fill Layer2 Info.*/
+ 	entry = ppe_fill_L2_info(eth, entry, hw_path);
+ 
++	if (skb_hnat_tops(skb) && hw_path->flags & FLOW_OFFLOAD_PATH_TNL)
++		goto hnat_entry_skip_bind;
++
++hnat_entry_bind:
+ 	/* Fill Info Blk*/
+ 	entry = ppe_fill_info_blk(eth, entry, hw_path);
+ 
+@@ -1806,7 +1878,20 @@ static unsigned int skb_to_hnat_info(str
+ 			entry.ipv6_5t_route.act_dp |= UDF_HNAT_PRE_FILLED;
+ 	}
+ 
++#if defined(CONFIG_MEDIATEK_NETSYS_V3)
++	hnat_fill_offload_engine_entry(skb, &entry);
++#endif
++
++hnat_entry_skip_bind:
+ 	wmb();
++
++	/*
++	 * final check before we write BIND info.
++	 * If this entry is already bound, we should not modify it right now
++	 */
++	if (entry_hnat_is_bound(foe))
++		return 0;
++
+ 	memcpy(foe, &entry, sizeof(entry));
+ 	/*reset statistic for this entry*/
+ 	if (hnat_priv->data->per_flow_accounting &&
+@@ -1859,6 +1944,7 @@ int mtk_sw_nat_hook_tx(struct sk_buff *s
+ 		return NF_ACCEPT;
+ 
+ 	eth = eth_hdr(skb);
++
+ 	memcpy(&bfib1_tx, &entry->bfib1, sizeof(entry->bfib1));
+ 
+ 	/*not bind multicast if PPE mcast not enable*/
+@@ -1878,6 +1964,12 @@ int mtk_sw_nat_hook_tx(struct sk_buff *s
+ 	switch ((int)bfib1_tx.pkt_type) {
+ 	case IPV4_HNAPT:
+ 	case IPV4_HNAT:
++		/*
++		 * skip if packet is an encap tnl packet or it may
++		 * screw up inner mac header
++		 */
++		if (skb_hnat_tops(skb) && skb_hnat_is_encap(skb))
++			break;
+ 		entry->ipv4_hnapt.smac_hi = swab32(*((u32 *)eth->h_source));
+ 		entry->ipv4_hnapt.smac_lo = swab16(*((u16 *)&eth->h_source[4]));
+ 		break;
+@@ -2037,6 +2129,10 @@ int mtk_sw_nat_hook_tx(struct sk_buff *s
+ 		entry->ipv6_5t_route.iblk2.dp = gmac_no;
+ 	}
+ 
++#if defined(CONFIG_MEDIATEK_NETSYS_V3)
++	hnat_fill_offload_engine_entry(skb, entry);
++#endif
++
+ 	bfib1_tx.ttl = 1;
+ 	bfib1_tx.state = BIND;
+ 	wmb();
+@@ -2058,6 +2154,7 @@ int mtk_sw_nat_hook_rx(struct sk_buff *s
+ 	}
+ 
+ 	skb_hnat_alg(skb) = 0;
++	skb_hnat_set_tops(skb, 0);
+ 	skb_hnat_magic_tag(skb) = HNAT_MAGIC_TAG;
+ 
+ 	if (skb_hnat_iface(skb) == FOE_MAGIC_WED0)
+@@ -2504,6 +2601,7 @@ static unsigned int mtk_hnat_nf_post_rou
+ 	struct flow_offload_hw_path hw_path = { .dev = (struct net_device*)out,
+ 						.virt_dev = (struct net_device*)out };
+ 	const struct net_device *arp_dev = out;
++	bool is_virt_dev = false;
+ 
+ 	if (xlat_toggle && !mtk_464xlat_post_process(skb, out))
+ 		return 0;
+@@ -2524,10 +2622,18 @@ static unsigned int mtk_hnat_nf_post_rou
+ 
+ 	if (out->netdev_ops->ndo_flow_offload_check) {
+ 		out->netdev_ops->ndo_flow_offload_check(&hw_path);
++
+ 		out = (IS_GMAC1_MODE) ? hw_path.virt_dev : hw_path.dev;
++		if (hw_path.flags & FLOW_OFFLOAD_PATH_TNL && mtk_tnl_encap_offload)
++			skb_hnat_set_tops(skb, hw_path.tnl_type + 1);
+ 	}
+ 
+ 	if (!IS_LAN_GRP(out) && !IS_WAN(out) && !IS_EXT(out))
++		is_virt_dev = true;
++
++	if (is_virt_dev
++	    && !(skb_hnat_tops(skb) && skb_hnat_is_encap(skb)
++		 && (hw_path.flags & FLOW_OFFLOAD_PATH_TNL)))
+ 		return 0;
+ 
+ 	trace_printk("[%s] case hit, %x-->%s, reason=%x\n", __func__,
+@@ -2547,9 +2653,18 @@ static unsigned int mtk_hnat_nf_post_rou
+ 		if (fn && !mtk_hnat_accel_type(skb))
+ 			break;
+ 
+-		if (fn && fn(skb, arp_dev, &hw_path))
++		if (!is_virt_dev && fn && fn(skb, arp_dev, &hw_path))
+ 			break;
+ 
++		/* skb_hnat_tops(skb) is updated in mtk_tnl_offload() */
++		if (skb_hnat_tops(skb)) {
++			if (skb_hnat_is_encap(skb) && !is_virt_dev
++			    && mtk_tnl_encap_offload && mtk_tnl_encap_offload(skb))
++				break;
++			if (skb_hnat_is_decap(skb))
++				break;
++		}
++
+ 		skb_to_hnat_info(skb, out, entry, &hw_path);
+ 		break;
+ 	case HIT_BIND_KEEPALIVE_DUP_OLD_HDR:
+@@ -2820,7 +2935,7 @@ mtk_hnat_ipv4_nf_local_out(void *priv, s
+ 	if (iph->protocol == IPPROTO_IPV6) {
+ 		entry->udib1.pkt_type = IPV6_6RD;
+ 		hnat_set_head_frags(state, skb, 0, hnat_set_alg);
+-	} else {
++	} else if (!skb_hnat_tops(skb)) {
+ 		hnat_set_head_frags(state, skb, 1, hnat_set_alg);
+ 	}
+ 
+--- a/drivers/net/ethernet/mediatek/mtk_hnat/nf_hnat_mtk.h
++++ b/drivers/net/ethernet/mediatek/mtk_hnat/nf_hnat_mtk.h
+@@ -44,7 +44,9 @@ struct hnat_desc {
+ 	u32 is_sp : 1;
+ 	u32 hf : 1;
+ 	u32 amsdu : 1;
+-	u32 resv3 : 19;
++	u32 tops : 6;
++	u32 is_decap : 1;
++	u32 resv3 : 12;
+ 	u32 magic_tag_protect : 16;
+ } __packed;
+ #elif defined(CONFIG_MEDIATEK_NETSYS_RX_V2)
+@@ -91,6 +93,19 @@ struct hnat_desc {
+ 	((((skb_headroom(skb) >= FOE_INFO_LEN) ? 1 : 0)))
+ 
+ #define skb_hnat_info(skb) ((struct hnat_desc *)(skb->head))
++#if defined(CONFIG_MEDIATEK_NETSYS_V3)
++#define skb_hnat_tops(skb) (((struct hnat_desc *)((skb)->head))->tops)
++#define skb_hnat_is_decap(skb) (((struct hnat_desc *)((skb)->head))->is_decap)
++#define skb_hnat_is_encap(skb) (!skb_hnat_is_decap(skb))
++#define skb_hnat_set_tops(skb, tops) ((skb_hnat_tops(skb)) = (tops))
++#define skb_hnat_set_is_decap(skb, is_decap) ((skb_hnat_is_decap(skb)) = (is_decap))
++#else /* !defined(CONFIG_MEDIATEK_NETSYS_V3) */
++#define skb_hnat_tops(skb) (0)
++#define skb_hnat_is_decap(skb) (0)
++#define skb_hnat_is_encap(skb) (0)
++#define skb_hnat_set_tops(skb, tops)
++#define skb_hnat_set_is_decap(skb, is_decap)
++#endif /* defined(CONFIG_MEDIATEK_NETSYS_V3) */
+ #define skb_hnat_magic(skb) (((struct hnat_desc *)(skb->head))->magic)
+ #define skb_hnat_reason(skb) (((struct hnat_desc *)(skb->head))->crsn)
+ #define skb_hnat_entry(skb) (((struct hnat_desc *)(skb->head))->entry)
+--- a/include/net/netfilter/nf_flow_table.h
++++ b/include/net/netfilter/nf_flow_table.h
+@@ -98,10 +98,22 @@ struct flow_offload {
+ #define FLOW_OFFLOAD_PATH_6RD		BIT(5)
+ #define FLOW_OFFLOAD_PATH_TNL		BIT(6)
+ 
++enum flow_offload_tnl {
++	FLOW_OFFLOAD_TNL_GRETAP,
++	FLOW_OFFLOAD_TNL_PPTP,
++	FLOW_OFFLOAD_TNL_IP_L2TP,
++	FLOW_OFFLOAD_TNL_UDP_L2TP_CTRL,
++	FLOW_OFFLOAD_TNL_UDP_L2TP_DATA,
++	FLOW_OFFLOAD_VXLAN,
++	FLOW_OFFLOAD_NATT,
++	__FLOW_OFFLOAD_MAX,
++};
++
+ struct flow_offload_hw_path {
+ 	struct net_device *dev;
+ 	struct net_device *virt_dev;
+ 	u32 flags;
++	u32 tnl_type;
+ 
+ 	u8 eth_src[ETH_ALEN];
+ 	u8 eth_dest[ETH_ALEN];
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+@@ -1868,6 +1868,9 @@ extern const struct of_device_id of_mtk_
+ extern u32 mtk_hwlro_stats_ebl;
+ extern u32 dbg_show_level;
+ 
++/* tunnel offload related */
++extern struct net_device *(*mtk_get_tnl_dev)(int tnl_idx);
++
+ /* read the hardware status register */
+ void mtk_stats_update_mac(struct mtk_mac *mac);
+ 
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4101-mtk-tops-network-service-error-recover-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4101-mtk-tops-network-service-error-recover-support.patch
new file mode 100644
index 0000000..fbb46ac
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4101-mtk-tops-network-service-error-recover-support.patch
@@ -0,0 +1,49 @@
+--- a/drivers/net/ethernet/mediatek/mtk_eth_reset.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_reset.c
+@@ -635,6 +635,9 @@ static int mtk_eth_netdevice_event(struc
+ 				   unsigned long event, void *ptr)
+ {
+ 	switch (event) {
++	case MTK_TOPS_DUMP_DONE:
++		complete(&wait_tops_done);
++		break;
+ 	case MTK_WIFI_RESET_DONE:
+ 	case MTK_FE_STOP_TRAFFIC_DONE:
+ 		pr_info("%s rcv done event:%lx\n", __func__, event);
+--- a/drivers/net/ethernet/mediatek/mtk_eth_reset.h
++++ b/drivers/net/ethernet/mediatek/mtk_eth_reset.h
+@@ -13,6 +13,7 @@
+ #define MTK_WIFI_RESET_DONE	0x2002
+ #define MTK_WIFI_CHIP_ONLINE 	0x2003
+ #define MTK_WIFI_CHIP_OFFLINE 	0x2004
++#define MTK_TOPS_DUMP_DONE	0x3001
+ #define MTK_FE_RESET_NAT_DONE	0x4001
+ 
+ #define MTK_FE_STOP_TRAFFIC	(0x2005)
+@@ -67,6 +68,7 @@ enum mtk_reset_event_id {
+ 
+ extern struct notifier_block mtk_eth_netdevice_nb __read_mostly;
+ extern struct completion wait_ser_done;
++extern struct completion wait_tops_done;
+ extern char* mtk_reset_event_name[32];
+ extern atomic_t reset_lock;
+ extern struct completion wait_nat_done;
+--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+@@ -38,6 +38,7 @@ atomic_t force = ATOMIC_INIT(0);
+ module_param_named(msg_level, mtk_msg_level, int, 0);
+ MODULE_PARM_DESC(msg_level, "Message level (-1=defaults,0=none,...,16=all)");
+ DECLARE_COMPLETION(wait_ser_done);
++DECLARE_COMPLETION(wait_tops_done);
+ 
+ #define MTK_ETHTOOL_STAT(x) { #x, \
+ 			      offsetof(struct mtk_hw_stats, x) / sizeof(u64) }
+@@ -4057,6 +4058,8 @@ static void mtk_pending_work(struct work
+ 				}
+ 			pr_warn("wait for MTK_FE_START_RESET\n");
+ 		}
++		if (!try_wait_for_completion(&wait_tops_done))
++			pr_warn("wait for MTK_TOPS_DUMP_DONE\n");
+ 		rtnl_lock();
+ 		break;
+ 	}
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4500-mtk-tops-gre-offload-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4500-mtk-tops-gre-offload-support.patch
new file mode 100644
index 0000000..3833fa0
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4500-mtk-tops-gre-offload-support.patch
@@ -0,0 +1,45 @@
+--- a/net/ipv4/ip_gre.c
++++ b/net/ipv4/ip_gre.c
+@@ -39,6 +39,7 @@
+ #include <net/inet_ecn.h>
+ #include <net/xfrm.h>
+ #include <net/net_namespace.h>
++#include <net/netfilter/nf_flow_table.h>
+ #include <net/netns/generic.h>
+ #include <net/rtnetlink.h>
+ #include <net/gre.h>
+@@ -901,6 +902,24 @@ static int ipgre_close(struct net_device
+ }
+ #endif
+ 
++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
++static int gre_dev_flow_offload_check(struct flow_offload_hw_path *path)
++{
++	struct net_device *dev = path->dev;
++	struct ip_tunnel *tunnel = netdev_priv(dev);
++
++	if (path->flags & FLOW_OFFLOAD_PATH_TNL)
++		return -EEXIST;
++
++	path->flags |= FLOW_OFFLOAD_PATH_TNL;
++	path->tnl_type = FLOW_OFFLOAD_TNL_GRETAP;
++	path->virt_dev = dev;
++	path->dev = tunnel->dev;
++
++	return 0;
++}
++#endif /* CONFIG_NF_FLOW_TABLE */
++
+ static const struct net_device_ops ipgre_netdev_ops = {
+ 	.ndo_init		= ipgre_tunnel_init,
+ 	.ndo_uninit		= ip_tunnel_uninit,
+@@ -1264,6 +1283,9 @@ static const struct net_device_ops gre_t
+ 	.ndo_get_stats64	= ip_tunnel_get_stats64,
+ 	.ndo_get_iflink		= ip_tunnel_get_iflink,
+ 	.ndo_fill_metadata_dst	= gre_fill_metadata_dst,
++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
++	.ndo_flow_offload_check = gre_dev_flow_offload_check,
++#endif
+ };
+ 
+ static int erspan_tunnel_init(struct net_device *dev)
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4500-mtk-tops-l2tp-offload-support.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4500-mtk-tops-l2tp-offload-support.patch
new file mode 100644
index 0000000..e6583b6
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/nf_hnat/999-4500-mtk-tops-l2tp-offload-support.patch
@@ -0,0 +1,35 @@
+--- a/net/l2tp/l2tp_core.c
++++ b/net/l2tp/l2tp_core.c
+@@ -1068,6 +1068,10 @@ int l2tp_xmit_skb(struct l2tp_session *s
+ 	int udp_len;
+ 	int ret = NET_XMIT_SUCCESS;
+ 
++#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
++	skb_reset_inner_headers(skb);
++#endif
++
+ 	/* Check that there's enough headroom in the skb to insert IP,
+ 	 * UDP and L2TP headers. If not enough, expand it to
+ 	 * make room. Adjust truesize.
+--- a/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
++++ b/drivers/net/ethernet/mediatek/mtk_hnat/hnat_nf_hook.c
+@@ -855,7 +855,8 @@ mtk_hnat_ipv4_nf_pre_routing(void *priv,
+ 	 * and it's L2TP flow, then do not bind.
+ 	 */
+ 	if (skb_hnat_iface(skb) == FOE_MAGIC_GE_VIRTUAL
+-	    && skb->dev->netdev_ops->ndo_flow_offload_check) {
++	    && skb->dev->netdev_ops->ndo_flow_offload_check
++	    && !mtk_tnl_decap_offload) {
+ 		skb->dev->netdev_ops->ndo_flow_offload_check(&hw_path);
+ 
+ 		if (hw_path.flags & FLOW_OFFLOAD_PATH_TNL)
+--- a/net/l2tp/l2tp_ppp.c
++++ b/net/l2tp/l2tp_ppp.c
+@@ -356,6 +356,7 @@ static int l2tp_ppp_flow_offload_check(s
+ 		return -EINVAL;
+ 
+ 	path->flags |= FLOW_OFFLOAD_PATH_TNL;
++	path->tnl_type = FLOW_OFFLOAD_TNL_UDP_L2TP_DATA;
+ 
+ 	return 0;
+ }
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2333-mtd-spinand-gigadevice-Add-support-for-F50L1G41LB-and-GD5F1GQ5UExxG.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2333-mtd-spinand-gigadevice-Add-support-for-F50L1G41LB-and-GD5F1GQ5UExxG.patch
deleted file mode 100644
index d37dd56..0000000
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2333-mtd-spinand-gigadevice-Add-support-for-F50L1G41LB-and-GD5F1GQ5UExxG.patch
+++ /dev/null
@@ -1,59 +0,0 @@
-From 39ee4e9fb5fd3ce678223147df9d9bef0ce822cd Mon Sep 17 00:00:00 2001
-From: Sam Shih <sam.shih@mediatek.com>
-Date: Fri, 2 Jun 2023 13:06:15 +0800
-Subject: [PATCH] 
- [spi-and-storage][999-2333-mtd-spinand-gigadevice-Add-support-for-F50L1G41LB-and-GD5F1GQ5UExxG.patch]
-
----
- drivers/mtd/nand/spi/gigadevice.c | 21 ++++++++++++++++++++-
- 1 file changed, 20 insertions(+), 1 deletion(-)
-
-diff --git a/drivers/mtd/nand/spi/gigadevice.c b/drivers/mtd/nand/spi/gigadevice.c
-index 937a04ce6..ce88f0c91 100644
---- a/drivers/mtd/nand/spi/gigadevice.c
-+++ b/drivers/mtd/nand/spi/gigadevice.c
-@@ -39,6 +39,15 @@ static SPINAND_OP_VARIANTS(read_cache_variants_f,
- 		SPINAND_PAGE_READ_FROM_CACHE_OP_3A(true, 0, 1, NULL, 0),
- 		SPINAND_PAGE_READ_FROM_CACHE_OP_3A(false, 0, 0, NULL, 0));
- 
-+/* Q5 devices, QUADIO: Dummy bytes only valid for 1 GBit variants */
-+static SPINAND_OP_VARIANTS(gd5f1gq5_read_cache_variants,
-+		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
-+		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
-+		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
-+		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
-+		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
-+		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
-+
- static SPINAND_OP_VARIANTS(write_cache_variants,
- 		SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
- 		SPINAND_PROG_LOAD(true, 0, NULL, 0));
-@@ -236,6 +245,16 @@ static int gd5fxgq4ufxxg_ecc_get_status(struct spinand_device *spinand,
- }
- 
- static const struct spinand_info gigadevice_spinand_table[] = {
-+	SPINAND_INFO("F50L1G41LB",
-+	             SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x01),
-+		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
-+		     NAND_ECCREQ(8, 512),
-+		     SPINAND_INFO_OP_VARIANTS(&gd5f1gq5_read_cache_variants,
-+					      &write_cache_variants,
-+					      &update_cache_variants),
-+		     0,
-+		     SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
-+				     gd5fxgq4xa_ecc_get_status)),
- 	SPINAND_INFO("GD5F1GQ4xA",
- 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xf1),
- 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
-@@ -290,7 +309,7 @@ static const struct spinand_info gigadevice_spinand_table[] = {
- 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x51),
- 		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
- 		     NAND_ECCREQ(4, 512),
--		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-+		     SPINAND_INFO_OP_VARIANTS(&gd5f1gq5_read_cache_variants,
- 					      &write_cache_variants,
- 					      &update_cache_variants),
- 		     SPINAND_HAS_QE_BIT,
--- 
-2.34.1
-
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2334-mtd-spinand-gigadevice-Add-support-for-GD5FxGQxUExxG-GD5FxGQxUExxH-and-GD5FxGMxUExxG-series.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2334-mtd-spinand-gigadevice-Add-support-for-GD5FxGQxUExxG-GD5FxGQxUExxH-and-GD5FxGMxUExxG-series.patch
deleted file mode 100644
index c609bd7..0000000
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2334-mtd-spinand-gigadevice-Add-support-for-GD5FxGQxUExxG-GD5FxGQxUExxH-and-GD5FxGMxUExxG-series.patch
+++ /dev/null
@@ -1,143 +0,0 @@
-From b8ffe42101eb8abfb6530396e0c74a85b43eed44 Mon Sep 17 00:00:00 2001
-From: Sam Shih <sam.shih@mediatek.com>
-Date: Fri, 2 Jun 2023 13:06:15 +0800
-Subject: [PATCH] 
- [spi-and-storage][999-2334-mtd-spinand-gigadevice-Add-support-for-GD5FxGQxUExxG-GD5FxGQxUExxH-and-GD5FxGMxUExxG-series.patch]
-
----
- drivers/mtd/nand/spi/gigadevice.c | 98 +++++++++++++++++++++++++++++--
- 1 file changed, 94 insertions(+), 4 deletions(-)
-
-diff --git a/drivers/mtd/nand/spi/gigadevice.c b/drivers/mtd/nand/spi/gigadevice.c
-index ce88f0c91..a4e89529d 100644
---- a/drivers/mtd/nand/spi/gigadevice.c
-+++ b/drivers/mtd/nand/spi/gigadevice.c
-@@ -39,8 +39,9 @@ static SPINAND_OP_VARIANTS(read_cache_variants_f,
- 		SPINAND_PAGE_READ_FROM_CACHE_OP_3A(true, 0, 1, NULL, 0),
- 		SPINAND_PAGE_READ_FROM_CACHE_OP_3A(false, 0, 0, NULL, 0));
- 
--/* Q5 devices, QUADIO: Dummy bytes only valid for 1 GBit variants */
--static SPINAND_OP_VARIANTS(gd5f1gq5_read_cache_variants,
-+/* For Q5 devices, QUADIO use different dummy byte settings */
-+/* Q5 1Gb */
-+static SPINAND_OP_VARIANTS(dummy2_read_cache_variants,
- 		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
- 		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
- 		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
-@@ -48,6 +49,15 @@ static SPINAND_OP_VARIANTS(gd5f1gq5_read_cache_variants,
- 		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
- 		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
- 
-+/* Q5 2Gb & 4Gb */
-+static SPINAND_OP_VARIANTS(dummy4_read_cache_variants,
-+		SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 4, NULL, 0),
-+		SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
-+		SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 2, NULL, 0),
-+		SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
-+		SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
-+		SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
-+
- static SPINAND_OP_VARIANTS(write_cache_variants,
- 		SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
- 		SPINAND_PROG_LOAD(true, 0, NULL, 0));
-@@ -249,7 +259,7 @@ static const struct spinand_info gigadevice_spinand_table[] = {
- 	             SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x01),
- 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
- 		     NAND_ECCREQ(8, 512),
--		     SPINAND_INFO_OP_VARIANTS(&gd5f1gq5_read_cache_variants,
-+		     SPINAND_INFO_OP_VARIANTS(&dummy2_read_cache_variants,
- 					      &write_cache_variants,
- 					      &update_cache_variants),
- 		     0,
-@@ -309,7 +319,87 @@ static const struct spinand_info gigadevice_spinand_table[] = {
- 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x51),
- 		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
- 		     NAND_ECCREQ(4, 512),
--		     SPINAND_INFO_OP_VARIANTS(&gd5f1gq5_read_cache_variants,
-+		     SPINAND_INFO_OP_VARIANTS(&dummy2_read_cache_variants,
-+					      &write_cache_variants,
-+					      &update_cache_variants),
-+		     SPINAND_HAS_QE_BIT,
-+		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
-+				     gd5fxgq5xexxg_ecc_get_status)),
-+	SPINAND_INFO("GD5F2GQ5UExxG",
-+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x52),
-+		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
-+		     NAND_ECCREQ(4, 512),
-+		     SPINAND_INFO_OP_VARIANTS(&dummy4_read_cache_variants,
-+					      &write_cache_variants,
-+					      &update_cache_variants),
-+		     SPINAND_HAS_QE_BIT,
-+		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
-+				     gd5fxgq5xexxg_ecc_get_status)),
-+	SPINAND_INFO("GD5F4GQ6UExxG",
-+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x55),
-+		     NAND_MEMORG(1, 2048, 128, 64, 4096, 80, 1, 1, 1),
-+		     NAND_ECCREQ(4, 512),
-+		     SPINAND_INFO_OP_VARIANTS(&dummy4_read_cache_variants,
-+					      &write_cache_variants,
-+					      &update_cache_variants),
-+		     SPINAND_HAS_QE_BIT,
-+		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
-+				     gd5fxgq5xexxg_ecc_get_status)),
-+	SPINAND_INFO("GD5F1GM7UExxG",
-+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x91),
-+		     NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
-+		     NAND_ECCREQ(8, 512),
-+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-+					      &write_cache_variants,
-+					      &update_cache_variants),
-+		     SPINAND_HAS_QE_BIT,
-+		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
-+				     gd5fxgq4uexxg_ecc_get_status)),
-+	SPINAND_INFO("GD5F2GM7UExxG",
-+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x92),
-+		     NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
-+		     NAND_ECCREQ(8, 512),
-+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-+					      &write_cache_variants,
-+					      &update_cache_variants),
-+		     SPINAND_HAS_QE_BIT,
-+		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
-+				     gd5fxgq4uexxg_ecc_get_status)),
-+	SPINAND_INFO("GD5F4GM8UExxG",
-+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x95),
-+		     NAND_MEMORG(1, 2048, 128, 64, 4096, 80, 1, 1, 1),
-+		     NAND_ECCREQ(8, 512),
-+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-+					      &write_cache_variants,
-+					      &update_cache_variants),
-+		     SPINAND_HAS_QE_BIT,
-+		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
-+				     gd5fxgq4uexxg_ecc_get_status)),
-+	SPINAND_INFO("GD5F1GQ5UExxH",
-+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x31),
-+		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
-+		     NAND_ECCREQ(4, 512),
-+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-+					      &write_cache_variants,
-+					      &update_cache_variants),
-+		     SPINAND_HAS_QE_BIT,
-+		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
-+				     gd5fxgq5xexxg_ecc_get_status)),
-+	SPINAND_INFO("GD5F2GQ5UExxH",
-+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x32),
-+		     NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
-+		     NAND_ECCREQ(4, 512),
-+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-+					      &write_cache_variants,
-+					      &update_cache_variants),
-+		     SPINAND_HAS_QE_BIT,
-+		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
-+				     gd5fxgq5xexxg_ecc_get_status)),
-+	SPINAND_INFO("GD5F4GQ6UExxH",
-+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x32),
-+		     NAND_MEMORG(1, 2048, 64, 64, 4096, 80, 1, 1, 1),
-+		     NAND_ECCREQ(4, 512),
-+		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
- 					      &write_cache_variants,
- 					      &update_cache_variants),
- 		     SPINAND_HAS_QE_BIT,
--- 
-2.34.1
-
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2335-mtd-spinand-fix-gigadevice-read-dummy.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2335-mtd-spinand-fix-gigadevice-read-dummy.patch
deleted file mode 100644
index 977c65c..0000000
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2335-mtd-spinand-fix-gigadevice-read-dummy.patch
+++ /dev/null
@@ -1,47 +0,0 @@
-From be41be0e740933fa976ad2990b94ef1e62542a8e Mon Sep 17 00:00:00 2001
-From: Sam Shih <sam.shih@mediatek.com>
-Date: Fri, 2 Jun 2023 13:06:15 +0800
-Subject: [PATCH] 
- [spi-and-storage][999-2335-mtd-spinand-fix-gigadevice-read-dummy.patch]
-
----
- drivers/mtd/nand/spi/gigadevice.c | 8 ++++----
- 1 file changed, 4 insertions(+), 4 deletions(-)
-
-diff --git a/drivers/mtd/nand/spi/gigadevice.c b/drivers/mtd/nand/spi/gigadevice.c
-index a4e89529d..b163ea5dc 100644
---- a/drivers/mtd/nand/spi/gigadevice.c
-+++ b/drivers/mtd/nand/spi/gigadevice.c
-@@ -379,7 +379,7 @@ static const struct spinand_info gigadevice_spinand_table[] = {
- 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x31),
- 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
- 		     NAND_ECCREQ(4, 512),
--		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-+		     SPINAND_INFO_OP_VARIANTS(&dummy2_read_cache_variants,
- 					      &write_cache_variants,
- 					      &update_cache_variants),
- 		     SPINAND_HAS_QE_BIT,
-@@ -389,17 +389,17 @@ static const struct spinand_info gigadevice_spinand_table[] = {
- 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x32),
- 		     NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
- 		     NAND_ECCREQ(4, 512),
--		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-+		     SPINAND_INFO_OP_VARIANTS(&dummy4_read_cache_variants,
- 					      &write_cache_variants,
- 					      &update_cache_variants),
- 		     SPINAND_HAS_QE_BIT,
- 		     SPINAND_ECCINFO(&gd5fxgqx_variant2_ooblayout,
- 				     gd5fxgq5xexxg_ecc_get_status)),
- 	SPINAND_INFO("GD5F4GQ6UExxH",
--		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x32),
-+		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35),
- 		     NAND_MEMORG(1, 2048, 64, 64, 4096, 80, 1, 1, 1),
- 		     NAND_ECCREQ(4, 512),
--		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
-+		     SPINAND_INFO_OP_VARIANTS(&dummy4_read_cache_variants,
- 					      &write_cache_variants,
- 					      &update_cache_variants),
- 		     SPINAND_HAS_QE_BIT,
--- 
-2.34.1
-
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2336-mtd-spinand-fix-F50L1G41LB-ecc-check.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2336-mtd-spinand-fix-F50L1G41LB-ecc-check.patch
deleted file mode 100644
index 644c6b3..0000000
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2336-mtd-spinand-fix-F50L1G41LB-ecc-check.patch
+++ /dev/null
@@ -1,27 +0,0 @@
-From c93adec4ad0e8ca47f1a622fb3a5ae445251af36 Mon Sep 17 00:00:00 2001
-From: Sam Shih <sam.shih@mediatek.com>
-Date: Fri, 2 Jun 2023 13:06:16 +0800
-Subject: [PATCH] 
- [spi-and-storage][999-2336-mtd-spinand-fix-F50L1G41LB-ecc-check.patch]
-
----
- drivers/mtd/nand/spi/gigadevice.c | 3 +--
- 1 file changed, 1 insertion(+), 2 deletions(-)
-
-diff --git a/drivers/mtd/nand/spi/gigadevice.c b/drivers/mtd/nand/spi/gigadevice.c
-index b163ea5dc..6ee569de2 100644
---- a/drivers/mtd/nand/spi/gigadevice.c
-+++ b/drivers/mtd/nand/spi/gigadevice.c
-@@ -263,8 +263,7 @@ static const struct spinand_info gigadevice_spinand_table[] = {
- 					      &write_cache_variants,
- 					      &update_cache_variants),
- 		     0,
--		     SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
--				     gd5fxgq4xa_ecc_get_status)),
-+		     SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout, NULL)),
- 	SPINAND_INFO("GD5F1GQ4xA",
- 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xf1),
- 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
--- 
-2.34.1
-
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2343-mtd-spinand-gigadevice-Add-support-for-F50L1G41LB.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2343-mtd-spinand-gigadevice-Add-support-for-F50L1G41LB.patch
new file mode 100644
index 0000000..acf4775
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/999-2343-mtd-spinand-gigadevice-Add-support-for-F50L1G41LB.patch
@@ -0,0 +1,20 @@
+Index: linux-5.4.246/drivers/mtd/nand/spi/gigadevice.c
+===================================================================
+--- linux-5.4.246.orig/drivers/mtd/nand/spi/gigadevice.c
++++ linux-5.4.246/drivers/mtd/nand/spi/gigadevice.c
+@@ -281,6 +281,15 @@ static int gd5fxgq4ufxxg_ecc_get_status(
+ }
+ 
+ static const struct spinand_info gigadevice_spinand_table[] = {
++	SPINAND_INFO("F50L1G41LB",
++	             SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x01),
++		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
++		     NAND_ECCREQ(8, 512),
++		     SPINAND_INFO_OP_VARIANTS(&read_cache_variants_1gq5,
++					      &write_cache_variants,
++					      &update_cache_variants),
++		     0,
++		     SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout, NULL)),
+ 	SPINAND_INFO("GD5F1GQ4xA",
+ 		     SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0xf1),
+ 		     NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/patches-5.4.inc b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/patches-5.4.inc
index 1fe0212..8f19163 100644
--- a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/patches-5.4.inc
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/patches-5.4/patches-5.4.inc
@@ -82,16 +82,13 @@
     file://999-2330-mtd-spinand-winbond-Support-for-W25MxxGV-W25NxxKV-series.patch \
     file://999-2331-mtd-spinand-macronix-suppress-mx35lf1ge4ab-warning-log.patch \
     file://999-2332-mtd-add-mtk-snand-driver.patch \
-    file://999-2333-mtd-spinand-gigadevice-Add-support-for-F50L1G41LB-and-GD5F1GQ5UExxG.patch \
-    file://999-2334-mtd-spinand-gigadevice-Add-support-for-GD5FxGQxUExxG-GD5FxGQxUExxH-and-GD5FxGMxUExxG-series.patch \
-    file://999-2335-mtd-spinand-fix-gigadevice-read-dummy.patch \
-    file://999-2336-mtd-spinand-fix-F50L1G41LB-ecc-check.patch \
     file://999-2337-mtd-spinor-support-EN25QX128A.patch \
     file://999-2338-mtd-tests-fix-pagetest-load.patch \
     file://999-2339-drivers-mtd-spinand-Add-calibration-support-for-spinand.patch \
     file://999-2340-drivers-mtd-spi-nor-Add-calibration-support-for-spi-nor.patch \
     file://999-2341-mtd-spinand-Add-support-etron.patch \
     file://999-2342-drivers-mtd-spi-nor-Add-support-EN25QX256A-2S.patch \
+    file://999-2343-mtd-spinand-gigadevice-Add-support-for-F50L1G41LB.patch \
     file://999-2350-nvmem-core-Add-functions-to-make-number-reading-easy.patch \
     file://999-2351-nvmem-mtk-efuse-support-minimum-one-byte-access-stri.patch \
     file://999-2361-add-spimem-support-to-mtk-spi.patch \
diff --git a/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3023-mtk-wed-add-dma-mask-limitation-and-GFP_DMA32-for-bo.patch b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3023-mtk-wed-add-dma-mask-limitation-and-GFP_DMA32-for-bo.patch
new file mode 100644
index 0000000..e27c903
--- /dev/null
+++ b/recipes-kernel/linux/linux-mediatek-5.4/mediatek/wed3/999-3023-mtk-wed-add-dma-mask-limitation-and-GFP_DMA32-for-bo.patch
@@ -0,0 +1,106 @@
+From 57294c4562d1f93ee2deaef67a2ad15fb925c288 Mon Sep 17 00:00:00 2001
+From: "sujuan.chen" <sujuan.chen@mediatek.com>
+Date: Wed, 19 Jul 2023 17:22:59 +0800
+Subject: [PATCH] mtk: wed: add dma mask limitation and GFP_DMA32 for board w/
+ >= 4GB dram
+
+Signed-off-by: sujuan.chen <sujuan.chen@mediatek.com>
+---
+ drivers/net/ethernet/mediatek/mtk_wed.c     | 8 ++++++--
+ drivers/net/ethernet/mediatek/mtk_wed_mcu.c | 4 ++--
+ drivers/net/ethernet/mediatek/mtk_wed_wo.c  | 4 ++--
+ drivers/net/ethernet/mediatek/mtk_wed_wo.h  | 1 +
+ 4 files changed, 11 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/net/ethernet/mediatek/mtk_wed.c b/drivers/net/ethernet/mediatek/mtk_wed.c
+index 45dfa0c..d4d8658 100644
+--- a/drivers/net/ethernet/mediatek/mtk_wed.c
++++ b/drivers/net/ethernet/mediatek/mtk_wed.c
+@@ -472,7 +472,7 @@ mtk_wed_tx_buffer_alloc(struct mtk_wed_device *dev)
+ 		void *buf;
+ 		int s;
+ 
+-		page = __dev_alloc_pages(GFP_KERNEL, 0);
++		page = __dev_alloc_pages(GFP_KERNEL | GFP_DMA32, 0);
+ 		if (!page)
+ 			return -ENOMEM;
+ 
+@@ -636,7 +636,7 @@ mtk_wed_rx_page_buffer_alloc(struct mtk_wed_device *dev)
+ 		void *buf;
+ 		int s;
+ 
+-		page = __dev_alloc_pages(GFP_KERNEL, 0);
++		page = __dev_alloc_pages(GFP_KERNEL | GFP_DMA32, 0);
+ 		if (!page)
+ 			return -ENOMEM;
+ 
+@@ -2239,6 +2239,10 @@ mtk_wed_attach(struct mtk_wed_device *dev)
+ 	dev->wdma_idx = hw->index;
+ 	dev->ver = hw->version;
+ 
++	ret = dma_set_mask_and_coherent(hw->dev, DMA_BIT_MASK(32));
++	if (ret)
++		return ret;
++
+ 	if (dev->hw->version == 3)
+ 		dev->hw->pci_base = mtk_wed_get_pci_base(dev);
+ 
+diff --git a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
+index 055594d..4ed1548 100644
+--- a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
++++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
+@@ -131,7 +131,7 @@ int mtk_wed_exception_init(struct mtk_wed_wo *wo)
+ 	}req;
+ 
+ 	exp->log_size = EXCEPTION_LOG_SIZE;
+-	exp->log = kmalloc(exp->log_size, GFP_ATOMIC);
++	exp->log = page_frag_alloc(&wo->page, exp->log_size, GFP_ATOMIC | GFP_DMA32);
+ 	if (!exp->log)
+ 		return -ENOMEM;
+ 
+@@ -151,7 +151,7 @@ int mtk_wed_exception_init(struct mtk_wed_wo *wo)
+ 				    &req, sizeof(req), false);
+ 
+ free:
+-	kfree(exp->log);
++	skb_free_frag(exp->log);
+ 	return -ENOMEM;
+ }
+ 
+diff --git a/drivers/net/ethernet/mediatek/mtk_wed_wo.c b/drivers/net/ethernet/mediatek/mtk_wed_wo.c
+index 54b7787..e991d20 100644
+--- a/drivers/net/ethernet/mediatek/mtk_wed_wo.c
++++ b/drivers/net/ethernet/mediatek/mtk_wed_wo.c
+@@ -88,7 +88,7 @@ woif_q_rx_fill(struct mtk_wed_wo *wo, struct wed_wo_queue *q, bool rx)
+ 		page = &q->rx_page;
+ 
+ 	while (q->queued < q->ndesc) {
+-		buf = page_frag_alloc(page, len, GFP_ATOMIC);
++		buf = page_frag_alloc(page, len, GFP_ATOMIC | GFP_DMA32);
+ 		if (!buf)
+ 			break;
+ 
+@@ -555,7 +555,7 @@ void mtk_wed_wo_exit(struct mtk_wed_hw *hw)
+ 
+ 	if (wo->exp.log) {
+ 		dma_unmap_single(wo->hw->dev, wo->exp.phys, wo->exp.log_size, DMA_FROM_DEVICE);
+-		kfree(wo->exp.log);
++		skb_free_frag(wo->exp.log);
+ 	}
+ 
+ 	wo->hw = NULL;
+diff --git a/drivers/net/ethernet/mediatek/mtk_wed_wo.h b/drivers/net/ethernet/mediatek/mtk_wed_wo.h
+index 548b38e..3fd1f3f 100644
+--- a/drivers/net/ethernet/mediatek/mtk_wed_wo.h
++++ b/drivers/net/ethernet/mediatek/mtk_wed_wo.h
+@@ -193,6 +193,7 @@ struct mtk_wed_wo {
+ 	const struct wed_wo_drv_ops *drv_ops;
+ 	const struct wed_wo_mcu_ops *mcu_ops;
+ 	const struct wed_wo_queue_ops *queue_ops;
++	struct page_frag_cache page;
+ 
+ 	struct net_device napi_dev;
+ 	spinlock_t rx_lock;
+-- 
+2.18.0
+